//! \~\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