/*////////////////////////////////////////////////////////////////////////////// // CMT Cosmic Muon Tomography project ////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova All rights reserved Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > ------------------------------------------------------------------ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. //////////////////////////////////////////////////////////////////////////////*/ #ifndef U_CORE_ALGORITHM_H #define U_CORE_ALGORITHM_H #include #include #include #include "Core/Object.h" #include "Core/Monitor.h" #include "Core/Threads.h" #include "Core/Property.h" namespace uLib { //////////////////////////////////////////////////////////////////////////////// //// ALGORITHM ///////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /** * @brief Algorithm is a template class for containing a functional that can be * dynamically loaded as a plug-in. It derives from Object and supports * properties for serialization and interactive parameter widgets. * * @tparam T_enc Encoder type: the input data type, or a chained algorithm * whose output is compatible with this algorithm's input. * @tparam T_dec Decoder type: the output data type, or a chained algorithm * whose input is compatible with this algorithm's output. */ template class Algorithm : public Object { public: using EncoderType = T_enc; using DecoderType = T_dec; Algorithm() : Object(), m_Encoder(nullptr), m_Decoder(nullptr) {} virtual ~Algorithm() = default; virtual const char* GetClassName() const override { return "Algorithm"; } /** * @brief Process input data and produce output. * Override this in subclasses to implement the algorithm logic. */ virtual T_dec Process(const T_enc& input) = 0; /** * @brief Operator form of Process for functional chaining. */ T_dec operator()(const T_enc& input) { return Process(input); } void SetEncoder(Algorithm* enc) { m_Encoder = enc; } Algorithm* GetEncoder() const { return m_Encoder; } void SetDecoder(Algorithm* dec) { m_Decoder = dec; } Algorithm* GetDecoder() const { return m_Decoder; } signals: virtual void Started() { ULIB_SIGNAL_EMIT(Algorithm::Started); } virtual void Finished() { ULIB_SIGNAL_EMIT(Algorithm::Finished); } protected: Algorithm* m_Encoder; Algorithm* m_Decoder; }; //////////////////////////////////////////////////////////////////////////////// //// ALGORITHM TASK //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /** * @brief AlgorithmTask manages the execution of an Algorithm within a * scheduled context. Uses uLib::Thread for execution and uLib::Mutex for * synchronization. Supports cyclic mode (with configurable period) and * asynchronous mode (triggered by Object signal-slot or condition variable * from Monitor.h). */ template class AlgorithmTask : public Thread { public: using AlgorithmType = Algorithm; enum Mode { Cyclic, Async }; AlgorithmTask() : Thread() , m_Algorithm(nullptr) , m_Mode(Cyclic) , m_CycleTime_ms(1000) , m_StopRequested(false) , m_Triggered(false) {} virtual ~AlgorithmTask() { Stop(); } virtual const char* GetClassName() const override { return "AlgorithmTask"; } void SetAlgorithm(AlgorithmType* alg) { m_Algorithm = alg; } AlgorithmType* GetAlgorithm() const { return m_Algorithm; } void SetMode(Mode mode) { m_Mode = mode; } Mode GetMode() const { return m_Mode; } void SetCycleTime(int milliseconds) { m_CycleTime_ms = milliseconds; } int GetCycleTime() const { return m_CycleTime_ms; } /** * @brief Start the task execution in a separate thread (via Thread::Start). * In Cyclic mode, the algorithm is executed periodically. * In Async mode, call Notify() or connect a signal to trigger execution. */ void Run(const T_enc& input) { if (IsRunning()) return; m_StopRequested.store(false); m_Triggered.store(false); m_Input = input; Start(); } /** * @brief Stop the task execution and join the thread. */ void Stop() { m_StopRequested.store(true); { ULIB_MUTEX_LOCK(m_WaitMutex, -1) { m_Condition.notify_all(); } } if (IsJoinable()) Join(); } /** * @brief Notify the task to execute one iteration (Async mode). * Can be called from a signal-slot connection or externally. */ void Notify() { m_Triggered.store(true); ULIB_MUTEX_LOCK(m_WaitMutex, -1) { m_Condition.notify_one(); } } /** * @brief Connect an Object signal to trigger async execution. * Usage: task.ConnectTrigger(sender, &SenderClass::SomeSignal); */ template Connection ConnectTrigger(typename FunctionPointer::Object* sender, Func1 sigf) { return Object::connect(sender, sigf, [this]() { Notify(); }); } signals: virtual void Stopped() { ULIB_SIGNAL_EMIT(AlgorithmTask::Stopped); } protected: /** * @brief Thread entry point — dispatches to cyclic or async loop. */ void Run() override { if (m_Mode == Cyclic) { RunCyclic(); } else { RunAsync(); } Stopped(); } private: void RunCyclic() { while (!m_StopRequested.load()) { if (m_Algorithm) { m_Algorithm->Process(m_Input); } std::unique_lock lock(m_WaitMutex.GetNative()); m_Condition.wait_for(lock, std::chrono::milliseconds(m_CycleTime_ms), [this]() { return m_StopRequested.load(); }); } } void RunAsync() { while (!m_StopRequested.load()) { std::unique_lock lock(m_WaitMutex.GetNative()); m_Condition.wait(lock, [this]() { return m_StopRequested.load() || m_Triggered.load(); }); if (m_StopRequested.load()) break; m_Triggered.store(false); if (m_Algorithm) { m_Algorithm->Process(m_Input); } } } AlgorithmType* m_Algorithm; Mode m_Mode; int m_CycleTime_ms; T_enc m_Input; std::atomic m_StopRequested; std::atomic m_Triggered; Mutex m_WaitMutex; std::condition_variable_any m_Condition; }; } // namespace uLib #endif // U_CORE_ALGORITHM_H