Files
pip/libs/main/thread/pithread.h

344 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\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