//! \~\file pithread.h //! \~\ingroup Thread //! \~\brief //! \~english Runtime thread object with optional loop execution //! \~russian Объект потока выполнения с необязательным циклом //! //! \~\details //! \~english //! %PIThread runs \a begin(), \a run() and \a end() on a dedicated system //! thread. In loop mode it also drains queued delivery addressed to the thread //! object as performer through \a maybeCallQueuedEvents() before each iteration. //! \~russian //! %PIThread выполняет \a begin(), \a run() и \a end() в отдельном системном //! потоке. В циклическом режиме он также обрабатывает отложенную доставку, //! адресованную объекту потока как исполнителю, через //! \a maybeCallQueuedEvents() перед каждой итерацией. /* 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 //! \~english Callback executed by %PIThread with the current \a data() pointer. //! \~russian Обратный вызов, который %PIThread выполняет с текущим указателем \a data(). typedef std::function ThreadFunc; //! \~\ingroup Thread //! \~\brief //! \~english Thread object that executes work on a dedicated system thread. //! \~russian Объект потока, выполняющий работу в отдельном системном потоке. //! \~\details //! \~english //! The default loop calls \a begin(), then repeats queued-delivery draining for //! this performer object plus \a run(), and finally calls \a end() when //! stopping. Use \a startOnce() when only one pass is needed and no repeated //! queued draining loop is required. //! \~russian //! Стандартный цикл вызывает \a begin(), затем повторяет обработку отложенной //! доставки для этого объекта-исполнителя вместе с \a run(), а при остановке //! вызывает \a end(). Используйте \a startOnce(), когда нужен только один //! проход без повторяющегося цикла обработки очереди. class PIP_EXPORT PIThread: public PIObject { PIOBJECT_SUBCLASS(PIThread, PIObject); #ifndef MICRO_PIP friend class PIIntrospectionThreads; #endif public: NO_COPY_CLASS(PIThread); //! \~english Constructs a thread with user data, callback and optional immediate start. //! \~russian Создает поток с пользовательскими данными, обратным вызовом и необязательным немедленным запуском. PIThread(void * data, ThreadFunc func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Constructs a thread with a callback without custom data. //! \~russian Создает поток с обратным вызовом без пользовательских данных. PIThread(std::function func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Constructs a subclass-oriented thread with an optional loop delay. //! \~russian Создает поток для наследования с необязательной задержкой цикла. PIThread(bool startNow = false, PISystemTime loop_delay = {}); //! \~english Destroys the thread object. If it is still running, destruction forces termination. //! \~russian Уничтожает объект потока. Если поток еще работает, при уничтожении выполняется принудительное завершение. virtual ~PIThread(); //! \~english Thread priority hint. //! \~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 Starts the thread with the stored callback and loop delay. //! \~russian Запускает поток с сохраненными обратным вызовом и задержкой цикла. bool start(); //! \~english Stores a new loop delay and starts the thread. //! \~russian Сохраняет новую задержку цикла и запускает поток. bool start(PISystemTime loop_delay); //! \~english Stores a callback and starts the thread. //! \~russian Сохраняет обратный вызов и запускает поток. bool start(ThreadFunc func); //! \~english Stores a callback and loop delay, then starts the thread. //! \~russian Сохраняет обратный вызов и задержку цикла, затем запускает поток. bool start(ThreadFunc func, PISystemTime loop_delay); //! \~english Stores a lambda callback and starts the thread. //! \~russian Сохраняет лямбда-обратный вызов и запускает поток. bool start(std::function func); //! \~english Stores a lambda callback and loop delay, then starts the thread. //! \~russian Сохраняет лямбда-обратный вызов и задержку цикла, затем запускает поток. bool start(std::function func, PISystemTime loop_delay); //! \~english Starts a one-shot thread without the repeating loop. //! \~russian Запускает одноразовый поток без повторяющегося цикла. bool startOnce(); //! \~english Stores a callback and starts one-shot execution. //! \~russian Сохраняет обратный вызов и запускает одноразовое выполнение. bool startOnce(ThreadFunc func); //! \~english Stores a lambda callback and starts one-shot execution. //! \~russian Сохраняет лямбда-обратный вызов и запускает одноразовое выполнение. bool startOnce(std::function func); //! \~english Deprecated overload of \a stopAndWait() that accepts milliseconds. //! \~russian Устаревшая перегрузка \a stopAndWait(), принимающая миллисекунды. bool stopAndWait(int timeout_ms) DEPRECATEDM("use stopAndWait(PISystemTime)") { return stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); } //! \~english Requests stop and waits for thread completion. Returns \b false if the timeout expires. //! \~russian Запрашивает остановку и ожидает завершения потока. Возвращает \b false, если таймаут истек. bool stopAndWait(PISystemTime timeout = {}); //! \~english Sets the data pointer passed to \a ThreadFunc callbacks. //! \~russian Устанавливает указатель данных, передаваемый в обратные вызовы \a ThreadFunc. void setData(void * d) { data_ = d; } //! \~english Sets the callback executed after each \a run() pass. //! \~russian Устанавливает обратный вызов, выполняемый после каждого прохода \a run(). void setSlot(ThreadFunc func) { ret_func = func; } //! \~english Sets a lambda callback executed after each \a run() pass. //! \~russian Устанавливает лямбда-обратный вызов, выполняемый после каждого прохода \a run(). void setSlot(std::function func) { ret_func = [func](void *) { func(); }; } //! \~english Sets the priority hint. If the thread is already running, applies it immediately. //! \~russian Устанавливает подсказку приоритета. Если поток уже работает, применяет ее немедленно. void setPriority(PIThread::Priority prior); //! \~english Returns the data pointer passed to \a ThreadFunc callbacks. //! \~russian Возвращает указатель данных, передаваемый в обратные вызовы \a ThreadFunc. void * data() const { return data_; } //! \~english Returns the configured priority hint. //! \~russian Возвращает настроенную подсказку приоритета. PIThread::Priority priority() const { return priority_; } //! \~english Returns whether the thread is currently running. //! \~russian Возвращает, выполняется ли поток в данный момент. bool isRunning() const { return running_; } //! \~english Returns whether stop has been requested and the thread is still finishing. //! \~russian Возвращает, был ли запрошен останов и поток еще завершает работу. bool isStopping() const { return running_ && terminating; } //! \~english Waits until the thread starts. Returns \b false if the timeout expires first. //! \~russian Ожидает запуска потока. Возвращает \b false, если таймаут истек раньше. bool waitForStart(PISystemTime timeout = {}); //! \~english Deprecated overload of \a waitForStart() that accepts milliseconds. //! \~russian Устаревшая перегрузка \a waitForStart(), принимающая миллисекунды. bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") { return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs)); } //! \~english Waits for thread completion. Returns \b false if the timeout expires first. //! \~russian Ожидает завершения потока. Возвращает \b false, если таймаут истек раньше. bool waitForFinish(PISystemTime timeout = {}); //! \~english Deprecated overload of \a waitForFinish() that accepts milliseconds. //! \~russian Устаревшая перегрузка \a waitForFinish(), принимающая миллисекунды. bool waitForFinish(int timeout_msecs) DEPRECATEDM("use waitForFinish(PISystemTime)") { return waitForFinish(PISystemTime::fromMilliseconds(timeout_msecs)); } //! \~english Enables locking of the internal mutex around \a begin(), \a run(), callbacks and \a end(). //! \~russian Включает блокировку внутреннего мьютекса вокруг \a begin(), \a run(), обратных вызовов и \a end(). void needLockRun(bool need) { lockRun = need; } //! \~english Returns the internal mutex used by \a lock(), \a unlock() and \a needLockRun(). //! \~russian Возвращает внутренний мьютекс, используемый \a lock(), \a unlock() и \a needLockRun(). PIMutex & mutex() const { return thread_mutex; } //! \~english Returns the system thread identifier, or -1 when the thread is not running. //! \~russian Возвращает системный идентификатор потока, либо -1 когда поток не запущен. llong tid() const { return tid_; } void __thread_func__(); void __thread_func_once__(); //! \~english Creates a temporary thread and invokes handler \a handler of object \a object on it. //! \~russian Создает временный поток и вызывает в нем обработчик \a handler объекта \a object. static void runOnce(PIObject * object, const char * handler, const PIString & name = PIString()); //! \~english Creates a temporary thread and runs [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) \a func on it. //! \~russian Создает временный поток и выполняет в нем [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) \a func. static void runOnce(std::function func, const PIString & name = PIString()); //! \handlers //! \{ //! \fn void stop() //! \brief //! \~english Requests graceful thread shutdown. //! \~russian Запрашивает корректное завершение потока. EVENT_HANDLER0(void, stop); //! \fn void terminate() //! \brief //! \~english Forces thread termination. Use only as a last resort. //! \~russian Принудительно прерывает поток. Используйте только как крайнюю меру. EVENT_HANDLER0(void, terminate); //! \fn void lock() //! \brief //! \~english Locks the internal mutex. //! \~russian Блокирует внутренний мьютекс. EVENT_HANDLER0(void, lock) const { thread_mutex.lock(); } //! \fn void unlock() //! \brief //! \~english Unlocks the internal mutex. //! \~russian Разблокирует внутренний мьютекс. EVENT_HANDLER0(void, unlock) const { thread_mutex.unlock(); } //! \} //! \events //! \{ //! \fn void started() //! \brief //! \~english Raised after the thread has started. //! \~russian Вызывается после запуска потока. EVENT(started); //! \fn void stopped() //! \brief //! \~english Raised when thread shutdown begins. //! \~russian Вызывается при начале завершения потока. EVENT(stopped); //! \} protected: static int priority2System(PIThread::Priority p); //! \~english Virtual method executed once after the system thread starts and before \a started(). //! \~russian Виртуальный метод, выполняемый один раз после запуска системного потока и до \a started(). virtual void begin() { ; } //! \~english Virtual method executed on each loop iteration until stop is requested. //! \~russian Виртуальный метод, выполняемый на каждой итерации цикла, пока не запрошен останов. virtual void run() { ; } //! \~english Virtual method executed once during thread shutdown after \a stopped(). //! \~russian Виртуальный метод, выполняемый один раз при завершении потока после \a stopped(). 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