342 lines
16 KiB
C++
342 lines
16 KiB
C++
//! \~\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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#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<PIThread *> threads() const;
|
||
void lock() { mutex.lock(); }
|
||
void unlock() { mutex.unlock(); }
|
||
void startedAuto(PIThread * t);
|
||
EVENT_HANDLER(void, stoppedAuto);
|
||
|
||
private:
|
||
PIVector<PIThread *> 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<void(void *)> 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<void()> 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<void()> func);
|
||
|
||
//! \~english Stores a lambda callback and loop delay, then starts the thread.
|
||
//! \~russian Сохраняет лямбда-обратный вызов и задержку цикла, затем запускает поток.
|
||
bool start(std::function<void()> 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<void()> 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<void()> 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<void()> 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
|