/*! \file pithread.h * \ingroup Thread * \~\brief * \~english Thread class * \~russian Класс потока */ /* PIP - Platform Independent Primitives Thread Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru This program 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 of the License, or (at your option) any later version. This program 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 program. If not, see . */ #ifndef PITHREAD_H #define PITHREAD_H #include "piinit.h" #include "pimutex.h" #include "piobject.h" #include "pithreadnotifier.h" class PIThread; #ifndef MICRO_PIP class PIIntrospectionThreads; class PIP_EXPORT __PIThreadCollection: public PIObject { PIOBJECT(__PIThreadCollection) public: static __PIThreadCollection * instance(); void registerThread(PIThread * t); void unregisterThread(PIThread * t); PIVector threads() const; void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } void startedAuto(PIThread * t); EVENT_HANDLER(void, stoppedAuto); private: PIVector threads_, auto_threads_; mutable PIMutex mutex, auto_mutex; }; class PIP_EXPORT __PIThreadCollection_Initializer__ { public: __PIThreadCollection_Initializer__(); ~__PIThreadCollection_Initializer__(); static int count_; static __PIThreadCollection * __instance__; }; static __PIThreadCollection_Initializer__ __PIThreadCollection_initializer__; #endif // MICRO_PIP typedef std::function ThreadFunc; class PIP_EXPORT PIThread: public PIObject { PIOBJECT_SUBCLASS(PIThread, PIObject); #ifndef MICRO_PIP friend class PIIntrospectionThreads; #endif public: NO_COPY_CLASS(PIThread); //! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay" //! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay" PIThread(void * data, ThreadFunc func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Contructs thread with external function "func" and main loop delay "loop_delay" //! \~russian Создает поток с функцией "func" и задержкой цикла "loop_delay" PIThread(std::function func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Contructs thread with main loop delay "loop_delay" //! \~russian Создает поток с задержкой цикла "loop_delay" PIThread(bool startNow = false, PISystemTime loop_delay = {}); virtual ~PIThread(); //! \~english Priority of thread //! \~russian Приоритет потока enum Priority { piLowerst /** \~english Lowest \~russian Низший */, piLow /** \~english Low \~russian Низкий */, piNormal /** \~english Normal, this is default priority of threads and timers \~russian Нормальный, это приоритет по умолчанию для потоков и таймеров */ , piHigh /** \~english High \~russian Высокий */, piHighest /** \~english Highest \~russian Высший */ }; //! \~english Start thread //! \~russian Запускает поток bool start(); //! \~english Start thread //! \~russian Запускает поток bool start(PISystemTime loop_delay); //! \~english Start thread //! \~russian Запускает поток bool start(ThreadFunc func); //! \~english Start thread //! \~russian Запускает поток bool start(ThreadFunc func, PISystemTime loop_delay); //! \~english Start thread //! \~russian Запускает поток bool start(std::function func); //! \~english Start thread //! \~russian Запускает поток bool start(std::function func, PISystemTime loop_delay); //! \~english Start thread without internal loop //! \~russian Запускает поток без внутреннего цикла bool startOnce(); //! \~english Start thread without internal loop //! \~russian Запускает поток без внутреннего цикла bool startOnce(ThreadFunc func); //! \~english Start thread without internal loop //! \~russian Запускает поток без внутреннего цикла bool startOnce(std::function func); EVENT_HANDLER0(void, stop); EVENT_HANDLER0(void, terminate); bool stopAndWait(int timeout_ms) DEPRECATEDM("use stopAndWait(PISystemTime)") { return stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); } //! \~english Stop thread and wait for finish. Returns \b false if timeout expired. //! \~russian Останавливает поток и ожидает завершения. Возвращает \b false если таймаут истек. bool stopAndWait(PISystemTime timeout = {}); //! \~english Set common data passed to external function //! \~russian Устанавливает данные, передаваемые в функцию потока void setData(void * d) { data_ = d; } //! \~english Set external function that will be executed after every \a run() //! \~russian Устанавливает функцию потока, вызываемую после каждого \a run() void setSlot(ThreadFunc func) { ret_func = func; } //! \~english Set external function that will be executed after every \a run() //! \~russian Устанавливает функцию потока, вызываемую после каждого \a run() void setSlot(std::function func) { ret_func = [func](void *) { func(); }; } //! \~english Set thread priority //! \~russian Устанавливает приоритет потока void setPriority(PIThread::Priority prior); //! \~english Returns common data passed to external function //! \~russian Возвращает данные, передаваемые в функцию потока void * data() const { return data_; } //! \~english Return thread priority //! \~russian Возвращает приоритет потока PIThread::Priority priority() const { return priority_; } //! \~english Return if thread is running //! \~russian Возвращает исполняется ли поток bool isRunning() const { return running_; } //! \~english Return if thread is stopping //! \~russian Возвращает останавливается ли поток bool isStopping() const { return running_ && terminating; } //! \~english Wait for thread start //! \~russian Ожидает старта потока bool waitForStart(PISystemTime timeout = {}); bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") { return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs)); } //! \~english Wait for thread finish. Returns \b false if timeout expired. //! \~russian Ожидает завершения потока. Возвращает \b false если таймаут истек. bool waitForFinish(PISystemTime timeout = {}); bool waitForFinish(int timeout_msecs) DEPRECATEDM("use waitForFinish(PISystemTime)") { return waitForFinish(PISystemTime::fromMilliseconds(timeout_msecs)); } //! \~english Set necessity of lock every \a run() with internal mutex //! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run() void needLockRun(bool need) { lockRun = need; } EVENT_HANDLER0(void, lock) const { thread_mutex.lock(); } EVENT_HANDLER0(void, unlock) const { thread_mutex.unlock(); } //! \~english Returns internal mutex //! \~russian Возвращает внутренний мьютекс PIMutex & mutex() const { return thread_mutex; } //! \~english Returns thread ID //! \~russian Возвращает ID потока llong tid() const { return tid_; } void __thread_func__(); void __thread_func_once__(); EVENT(started); EVENT(stopped); //! \~english Call event handler "handler" of object "object" in separate thread //! \~russian Вызывает обработчик "handler" объекта "object" в отдельном потоке static void runOnce(PIObject * object, const char * handler, const PIString & name = PIString()); //! \~english Call [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in separate thread //! \~russian Вызывает [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в отдельном потоке static void runOnce(std::function func, const PIString & name = PIString()); //! \handlers //! \{ //! \fn void stop() //! \brief //! \~english Stop thread //! \~russian Останавливает поток //! \fn void terminate() //! \brief //! \~english Strongly stop thread //! \~russian Жёстко прерывает поток //! \fn void lock() //! \brief //! \~english Lock internal mutex //! \~russian Блокирует внутренний мьютекс //! \fn void unlock() //! \brief //! \~english Unlock internal mutex //! \~russian Разблокирует внутренний мьютекс //! \} //! \events //! \{ //! \fn void started() //! \brief //! \~english Raise on thread start //! \~russian Вызывается при старте потока //! \fn void stopped() //! \brief //! \~english Raise on thread stop //! \~russian Вызывается при завершении потока //! \} protected: static int priority2System(PIThread::Priority p); //! \~english Function executed once at the start of thread //! \~russian Метод выполняется один раз при старте потока virtual void begin() { ; } //! \~english Function executed at every "loop_delay" msecs until thread was stopped //! \~russian Метод выполняется каждые "loop_delay" миллисекунд virtual void run() { ; } //! \~english Function executed once at the end of thread //! \~russian Метод выполняется один раз при остановке потока virtual void end() { ; } std::atomic_bool terminating, running_, lockRun; PISystemTime delay_; llong tid_ = -1; void * data_ = nullptr; mutable PIMutex thread_mutex; PIThread::Priority priority_ = piNormal; ThreadFunc ret_func = nullptr; PIThreadNotifier state_notifier; PRIVATE_DECLARATION(PIP_EXPORT) private: bool _startThread(void * func); void _beginThread(); void _runThread(); void _endThread(); bool _waitForFinish(PISystemTime max_tm); PIByteArray createThreadName(int size = 16) const; void setThreadName(); }; #endif // PITHREAD_H