thread doc ru

This commit is contained in:
2022-04-21 22:26:49 +03:00
parent 93b881da1b
commit 9deae168a6
7 changed files with 468 additions and 97 deletions

View File

@@ -31,13 +31,20 @@
//! \~russian \section PIMutex_sec0 Краткий обзор
//!
//! \~english
//! %PIMutex provides synchronization blocks between several threads.
//! %PIMutex provides critical code section defence between several threads.
//! Using mutex guarantees execution of some code only one of threads.
//! Mutex contains logic state and functions to change it: \a lock(),
//! \a unlock() and \a tryLock().
//!
//! \~russian
//! For automatic lock-unlock use \a PIMutexLocker.
//!
//! \~russian
//! %PIMutex предоставляет межпотоковую защиту критических секций кода.
//! Использование мьютекса гарантирует выполнение секции только один потоком.
//! Мьютекс состоит из логического состояния и методов для его изменения:
//! \a lock(), \a unlock() and \a tryLock().
//!
//! Для автоматической блокировки-разблокировки используйте \a PIMutexLocker.
//!
//! \~english \section PIMutex_sec1 Usage
//! \~russian \section PIMutex_sec1 Использование
@@ -47,11 +54,15 @@
//! should to be started with \a lock() and finished with \a unlock().
//!
//! \~russian
//! Части кода, которые должны быть выполнены только одним потоком в любой момент
//! времени должны начинаться с вызова \a lock() и заканчиваться вызовом \a unlock().
//!
//! \~\code
//! // critical section start
//! mutex.lock();
//! // ... your code here
//! mutex.unlock();
//! // critical section end
//! \endcode
//! \}
@@ -68,14 +79,31 @@
//! \~\details
//!
//! \~english
//! When a PIMutexLocker object is created, it attempts to lock the mutex it is given, if "condition" true.
//! When control leaves the scope in which the PIMutexLocker object was created,
//! the PIMutexLocker is destructed and the mutex is released, if "condition" true.
//! If "condition" false this class do nothing.
//! The PIMutexLocker class is non-copyable.
//! When a %PIMutexLocker object is created, it attempts to lock the mutex it is given, if "condition" \c true.
//! When control leaves the scope in which the %PIMutexLocker object was created,
//! the %PIMutexLocker is destructed and the mutex is released, if "condition" was \c true.
//!
//! If "condition" \c false this class do nothing.
//!
//! The %PIMutexLocker class is non-copyable.
//!
//! \~russian
//! При создании экземпляра %PIMutexLocker блокируется переданный мьютекс, если "condition" \c true.
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и мьютекс
//! разблокируется, если "condition" был \c true.
//!
//! Если "condition" \c false, то этот объект ничего не делает.
//!
//! Класс %PIMutexLocker некопируемый.
//!
//! \~\code
//! // critical section start
//! {
//! PIMutexLocker locker(mutex);
//! // ... your code here
//! }
//! // critical section end
//! \endcode
//! \}
@@ -118,6 +146,8 @@ PIMutex::~PIMutex() {
//! If mutex is unlocked it set to locked state and returns immediate.
//! If mutex is already locked function blocks until mutex will be unlocked
//! \~russian
//! Если мьютекс свободен, то блокирует его и возвращает управление немедленно.
//! Если мьютекс заблокирован, то ожидает разблокировки, затем блокирует и возвращает управление
void PIMutex::lock() {
#if defined(WINDOWS)
EnterCriticalSection(&(PRIVATE->mutex));
@@ -133,6 +163,7 @@ void PIMutex::lock() {
//! \~english
//! In any case this function returns immediate
//! \~russian
//! В любом случае возвращает управление немедленно
void PIMutex::unlock() {
#if defined(WINDOWS)
LeaveCriticalSection(&(PRIVATE->mutex));

View File

@@ -72,11 +72,11 @@ public:
NO_COPY_CLASS(PIMutexLocker)
//! \~english Constructs and lock "m" if "condition" is \c true
//! \~russian
//! \~russian Создает и блокирует мьютекс "m" если "condition" \c true
PIMutexLocker(PIMutex & m, bool condition = true): mutex(m), cond(condition) {if (cond) mutex.lock();}
//! \~english Unlock "m" if "condition" was \c true
//! \~russian
//! \~russian Разблокирует мьютекс "m" если "condition" был \c true
~PIMutexLocker() {if (cond) mutex.unlock();}
private:

View File

@@ -27,11 +27,18 @@
//!
//! \~\details
//! \~english
//! %PISpinlock provides synchronization blocks between several threads.
//! PISpinlock functionality similar to PIMutex, but working on atomic
//! type and \a lock() method wait with 100% CPU load.
//! %PISpinlock provides critical code section defence between several threads.
//! %PISpinlock functionality similar to PIMutex, but working on atomic
//! type and \a lock() method wait with 100% CPU core load.
//!
//! For automatic lock-unlock use \a PISpinlockLocker.
//!
//! \~russian
//! %PISpinlock предоставляет межпотоковую защиту критических секций кода.
//! Функционально он аналогичен PIMutex, однако работает на атомарном типе
//! и ожидание разблокировки в методе \a lock() нагружает ядро ЦП на 100%.
//!
//! Для автоматической блокировки-разблокировки используйте \a PISpinlockLocker.
//!
//! \~\note
//! \~english
@@ -39,6 +46,8 @@
//! important than CPU load!
//!
//! \~russian
//! Используйте этот класс вместо PIMutex когда время ожидания гораздо важнее
//! чем нагрузка на ЦП!
//!
//! \}
@@ -49,17 +58,26 @@
//!
//! \~\brief
//! \~english %PISpinlock autolocker
//! \~russian
//! \~russian Автоблокировщик %PISpinlock
//!
//!
//! \~\details
//! \~english
//! When a PISpinlockLocker object is created, it attempts to lock the spinlock it is given, if "condition" true.
//! When control leaves the scope in which the PISpinlockLocker object was created,
//! the PISpinlockLocker is destructed and the spinlock is released, if "condition" true.
//! When a %PISpinlockLocker object is created, it attempts to lock the spinlock it is given, if "condition" true.
//! When control leaves the scope in which the %PISpinlockLocker object was created,
//! the %PISpinlockLocker is destructed and the spinlock is released, if "condition" true.
//!
//! If "condition" false this class do nothing.
//! The PISpinlockLocker class is non-copyable.
//!
//! The %PISpinlockLocker class is non-copyable.
//!
//! \~russian
//! При создании экземпляра %PISpinlockLocker блокируется переданный спинлок, если "condition" \c true.
//! Когда выполнение покидает область жизни объекта, вызывается его деструктор и спинлок
//! разблокируется, если "condition" был \c true.
//!
//! Если "condition" \c false, то этот объект ничего не делает.
//!
//! Класс %PISpinlockLocker некопируемый.
//!
//! \}

View File

@@ -36,29 +36,32 @@ public:
NO_COPY_CLASS(PISpinlock)
//! \~english Constructs unlocked spinlock
//! \~russian
//! \~russian Создает незаблокированный спинлок
explicit PISpinlock() {flag.clear();}
//! \~english Destroy spinlock
//! \~russian
//! \~russian Деструктор спинлока
~PISpinlock() {}
//! \~english Lock spinlock
//! \~russian
//! \~russian Блокирует спинлок
//! \~\details
//! \~english
//! If spinlock is unlocked it set to locked state and returns immediate.
//! If spinlock is already locked function blocks until spinlock will be unlocked
//! \~russian
//! Если спинлок свободен, то блокирует его и возвращает управление немедленно.
//! Если спинлок заблокирован, то ожидает разблокировки, затем блокирует и возвращает управление
void lock() {while (flag.test_and_set(std::memory_order_acquire));}
//! \~english Unlock spinlock
//! \~russian
//! \~russian Разблокирует спинлок
//! \~\details
//! \~english
//! In any case this function returns immediate
//! \~russian
//! В любом случае возвращает управление немедленно
void unlock() {flag.clear(std::memory_order_release);}
private:
@@ -73,11 +76,11 @@ public:
NO_COPY_CLASS(PISpinlockLocker)
//! \~english Constructs and lock "s" if "condition" is \c true
//! \~russian
//! \~russianСоздает и блокирует спинлок "m" если "condition" \c true
PISpinlockLocker(PISpinlock & s, bool condition = true): spinlock(s), cond(condition) {if (cond) spinlock.lock();}
//! \~english Unlock "s" if "condition" was \c true
//! \~russian
//! \~russian Разблокирует спинлок "m" если "condition" был \c true
~PISpinlockLocker() {if (cond) spinlock.unlock();}
private:

View File

@@ -72,30 +72,62 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun
//! \~english \section PIThread_sec0 Synopsis
//! \~russian \section PIThread_sec0 Краткий обзор
//! \~english
//! Multithreading allow you to write program which will be executed
//! Multithreading allow you to execute code
//! in several threads simultaneously. This trend allow you to use all
//! cores of modern processors, but there are many dangers.
//!
//! This class provide virtual functions \a begin(), \a run() and \a end(),
//! which describes start, execution and finish work of some process.
//! These functions executes in \b separate thread. When you execute
//! \a start(), %PIThread create separate system thread and sequentially
//! \a start(int), %PIThread create separate system thread and sequentially
//! executes function \a begin(), \a run() and \a end(). You can
//! reimplement each function and write your own code to execute.
//!
//! Scheme of functions executing:
//!
//! \~russian
//! Многопоточность позволяет исполнять код в нескольких потоках
//! одновременно и использовать все ядра современных процессоров.
//! Однако это таит в себе опасности.
//!
//! Этот класс предоставляет виртуальные методы \a begin(), \a run() и \a end(),
//! которые описывают старт, выполнение и завершение потоковой задачи.
//! Все эти методы исполняются в \b отдельном потоке. Когда выполняется
//! \a start(int), %PIThread создает отдельный поток средствами ОС и последовательно
//! выполняет \a begin(), \a run() и \a end(). Можно переопределить каждый метод
//! для реализации нужной задачи.
//!
//! Схема выполнения методов:
//!
//! \~\code{.cpp}
//! begin();
//! event started();
//! while (isRunning()) {
//! run();
//! ThreadFunc();
//! piMSleep(timer_delay);
//! virtual begin()
//! event started()
//! while (isRunning()) { // while not stop()
//! virtual run()
//! ThreadFunc() // Slot or lambda
//! piMSleep(timer_delay) // if timer_delay > 0
//! }
//! event stopped();
//! end();
//! event stopped()
//! virtual end()
//! \endcode
//!
//! \~english
//! If no internal loop needed, you can use \a startOnce() method instead of \a start(int).
//!
//! In this case scheme is next:
//!
//! \~russian
//! Если внутренний цикл не нужен, то можно использовать метод \a startOnce() вместо \a start(int).
//!
//! В этом случает схема выполнения следущая:
//!
//! \~\code{.cpp}
//! virtual begin()
//! event started()
//! virtual run()
//! ThreadFunc() // Slot or lambda
//! event stopped()
//! virtual end()
//! \endcode
//!
//! \~english
@@ -106,6 +138,67 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun
//! and \a end() functions.
//!
//! \~russian
//! В отличии от прямого использования "pthread" или похожих механизмов
//! нет необходимости писать свой цикл внутри поточного метода и ожидать
//! в его теле. %PIThread уже рализует такой цикл, необходимо лишь
//! установить значение ожидания в конструкторе или при запуске потока,
//! и переопределить методы \a begin(), \a run() и \a end().
//!
//! \~english Using with internal loop
//! \~russian Использование с внутренним циклом
//! \~\code{.cpp}
//! class MyThread: public PIThread {
//! PIOBJECT_SUBCLASS(MyThread, PIThread)
//! public:
//! void begin() override {piCout << "thread begin";}
//! void run() override {piCout << "thread run" << ++cnt;}
//! void end() override {piCout << "thread end";}
//! private:
//! int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyThread mt;
//! mt.start(100);
//! piMSleep(500);
//! mt.stop(true);
//! return 0;
//! }
//!
//! // thread begin
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! // thread end
//! \endcode
//!
//! \~english Using without internal loop
//! \~russian Использование без внутреннего цикла
//! \~\code{.cpp}
//! class MyThread: public PIThread {
//! PIOBJECT_SUBCLASS(MyThread, PIThread)
//! public:
//! void begin() override {piCout << "thread begin";}
//! void run() override {piCout << "thread run" << ++cnt;}
//! void end() override {piCout << "thread end";}
//! private:
//! int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyThread mt;
//! mt.startOnce();
//! piMSleep(500);
//! mt.stop(true);
//! return 0;
//! }
//!
//! // thread begin
//! // thread run 1
//! // thread end
//! \endcode
//!
//!
//! \~english \section PIThread_sec1 Using without subclassing
@@ -113,27 +206,243 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun
//! \~english
//! You can use %PIThread without subclassing by using "ThreadFunc" pointer
//! that can be set from constructor or by overloaded function \a start(ThreadFunc func, int timer_delay).
//! If "func" if not null this function will be executed as \a run(). ThreadFunc is any static
//! function with format void func(void * data). "Data" is custom data set from constructor or
//! with function \a setData(). \n Also you can connect to event \a started(), but
//! in this case you should to white your thread main cycle, because this event raised only one time.
//! If "func" if not null this function will be executed after \a run().
//!
//! ThreadFunc is any static function with format "void func(void * data)", or
//! lambda-function with format [...]( ){...}.
//! "Data" is custom data set from constructor or with \a setData() function.
//!
//! Also you can connect to event \a started(), but in this case you should to white
//! your thread main cycle, because this event raised only one time after thread start.
//!
//! \~russian
//! Возможно использовать %PIThread без наследования. Можно передать ему в конструкторе
//! или при запуске указатель на внешний метод "ThreadFunc". В основном цикле потока,
//! если "ThreadFunc" существует, он будет вызываться после \a run().
//!
//! ThreadFunc может быть любым статическим методом в формате "void func(void * data)", либо
//! лямбда-функцией в формате [...]( ){...}.
//! "Data" является произвольным указателем, задаваемым в конструкторе или методом \a setData().
//!
//! Также можно присоединиться к событию \a started(), но в этом случае надо будет своими силами
//! реализовать весь цикл, т.к. это событие вызывается один раз после запуска потока.
//!
//! \~english Using with internal loop
//! \~russian Использование с внутренним циклом
//! \~\code{.cpp}
//! void myThreadFunc(void * d) {
//! int * cnt = (int*)d;
//! piCout << "thread run" << ++(*cnt);
//! }
//!
//! int main(int argc, char * argv[]) {
//! int cnt = 0;
//! PIThread mt;
//! mt.setData(&cnt);
//! mt.start(myThreadFunc, 100);
//! piMSleep(500);
//! mt.stop(true);
//! return 0;
//! }
//!
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! \endcode
//!
//! \~english Using without internal loop
//! \~russian Использование без внутреннего цикла
//! \~\code{.cpp}
//! void myThreadFunc(void * d) {
//! int * cnt = (int*)d;
//! piCout << "thread run" << ++(*cnt);
//! }
//!
//! int main(int argc, char * argv[]) {
//! int cnt = 0;
//! PIThread mt;
//! mt.setData(&cnt);
//! mt.startOnce(myThreadFunc);
//! piMSleep(500);
//! mt.stop(true);
//! return 0;
//! }
//!
//! // thread run 1
//! \endcode
//!
//! \~english Using with lambda-function
//! \~russian Использование с лямбда-функцией
//! \~\code{.cpp}
//! int main(int argc, char * argv[]) {
//! int cnt = 0;
//! PIThread mt;
//! mt.start([&cnt](){
//! piCout << "thread run" << ++cnt;
//! }, 100);
//! piMSleep(500);
//! mt.stop(true);
//! return 0;
//! }
//!
//! // thread run 1
//! // thread run 2
//! // thread run 3
//! // thread run 4
//! // thread run 5
//! \endcode
//!
//! \~english Using with event
//! \~russian Использование с событием
//! \~\code{.cpp}
//! class MyObj: public PIObject {
//! PIOBJECT(MyObj)
//! public:
//! EVENT_HANDLER(void, threadRun) {
//! piForTimes (5) {
//! piCout << "threadRun" << ++cnt;
//! piMSleep(100);
//! }
//! };
//! private:
//! int cnt = 0;
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyObj mo;
//! PIThread mt;
//! CONNECTU(&mt, started, &mo, threadRun);
//! mt.startOnce();
//! mt.stop(true);
//! return 0;
//! }
//!
//! // threadRun 1
//! // threadRun 2
//! // threadRun 3
//! // threadRun 4
//! // threadRun 5
//! \endcode
//!
//! \~english \section PIThread_sec2 Locking
//! \~russian \section PIThread_sec2 Блокировки
//! \~english
//! %PIThread has inrternal mutex that can be locked and unlocked every \a run() if you set this flag
//! with function \a needLockRun(bool). Also you can access to this mutex by functions \a lock(), \a unlock()
//! and \a mutex(). Using this functions together with needLockRun(true) can guarantee one-thread access to
//! some data.
//! with function \a needLockRun(true). Also you can access to this mutex by functions \a lock(), \a unlock()
//! and \a mutex(). Using this functions outside of thread together with \a needLockRun(true) can defend
//! your data.
//!
//! \~russian
//! %PIThread имеет встроенный мьютекс, который может блокироваться и разблокироваться каждый \a run()
//! при установленном \a needLockRun(true). К нему есть доступ через методы \a lock(), \a unlock() и \a mutex().
//! Использование этих методов вне потока совместно с \a needLockRun(true) поможет защитить данные.
//!
//! \}
//!
//! \fn bool PIThread::start(int timer_delay = -1)
//! \~\details
//! \~english
//! Start execution of \a run() in internal loop with
//! "timer_delay" delay in milliseconds. If "timer_delay" <= 0
//! this is no delay in loop. Thread also exec external function
//! set by \a setSlot() if it`s not null.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Начинает выполнение \a run() во внутреннем цикле
//! с задержкой "timer_delay" миллисекунд. Если "timer_delay" <= 0
//! то задержки не будет. Также поток вызывает внешний метод,
//! заданный через \a setSlot(), если он существует.
//! \return \c false если поток уже запущен или не может запуститься
//! \fn bool PIThread::startOnce()
//! \~\details
//! \~english
//! Start execution of \a run() once. Thread also exec
//! external function set by \a setSlot() if it`s not null.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Начинает выполнение \a run() один раз. Также поток вызывает
//! внешний метод, заданный через \a setSlot(), если он существует.
//! \return \c false если поток уже запущен или не может запуститься
//! \fn bool PIThread::startOnce(ThreadFunc func)
//! \~\details
//! \~english
//! Overloaded function. Set external function "func" before start.
//! \return \c false if thread already started or can`t start thread
//!
//! \~russian
//! Перегрузка метода, устанавливает внешний метод в "func" перед запуском.
//! \return \c false если поток уже запущен или не может запуститься
//! \fn void PIThread::stop(bool wait = false)
//! \~\details
//! \~english
//! Mark thread to stop execution and wait for finish
//! if "wait" is \c true. Thread can be stopped only outside of
//! \a run() or external method.
//! \warning This function can block for infinite
//! time if "wait" is \c true and any of thread function is
//! busy forever.
//!
//! \~russian
//! Помечает поток на остановку и ожидает завершения если
//! "wait" \c true. Поток может быть остановлен только вне
//! \a run() или внешнего метода.
//! \warning Этот метод может ожидать бесконечно если
//! "wait" \c true и любой из потоковых методов занят навечно.
//! \fn void PIThread::terminate()
//! \~\details
//! \~english
//! Stop execution of thread immediately.
//! \warning Memory can be corrupted, try not to use this method!
//!
//! \~russian
//! Немедленно останавливает поток.
//! \warning Это может повредить память, старайтесь не использовать этот метод!
//! \fn bool PIThread::waitForStart(int timeout_msecs = -1)
//! \~\details
//! \~english
//! Block until thread start within "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c true if thread started less than timeout
//! \return \c false if timeout is exceeded
//!
//! \~russian
//! Блокирует до тех пор, пока поток не запустится в течении
//! "timeout_msecs", или бесконечно, если "timeout_msecs" < 0
//! \return \c true если поток запустился менее чем за таймаут
//! \return \c false если таймаут истёк
//! \fn bool PIThread::waitForFinish(int timeout_msecs = -1)
//! \~\details
//! \~english
//! Block until thread finish for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c true if thread finished less than timeout
//! \return \c false if timeout is exceeded
//!
//! \~russian
//! Блокирует до тех пор, пока поток не завершится в течении
//! "timeout_msecs", или бесконечно, если "timeout_msecs" < 0
//! \return \c true если поток завершился менее чем за таймаут
//! \return \c false если таймаут истёк
#ifndef MICRO_PIP
__PIThreadCollection *__PIThreadCollection::instance() {
@@ -614,6 +923,36 @@ void PIThread::__thread_func_once__() {
}
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! event handler "handler" of object "object" in this thread.\n
//! This %PIThread automatically delete on function finish.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! обработчик "handler" объекта "object" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения обработчика.
//!
//! \~\code
//! class MyObj: public PIObject {
//! PIOBJECT(MyObj)
//! public:
//! EVENT_HANDLER(void, threadRun) {
//! piForTimes (5) {
//! piCout << "threadRun";
//! piMSleep(100);
//! }
//! };
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyObj mo;
//! PIThread::runOnce(&mo, "threadRun");
//! piMSleep(1000); // wait for thread finish
//! return 0;
//! }
//! \endcode
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);
@@ -629,6 +968,28 @@ void PIThread::runOnce(PIObject * object, const char * handler, const PIString &
}
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! lambda-function "func" in this thread.\n
//! This %PIThread automatically delete on function finish.\n
//! "func" shouldn`t have arguments.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! лямбда-функцию "func" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения функции.\n
//! "func" не должна иметь аргументов.
//!
//! \~\code
//! PIThread::runOnce([](){
//! piForTimes(5) {
//! piCout << "thread func";
//! piMSleep(100);
//! }
//! });
//! piMSleep(1000);
//! \endcode
void PIThread::runOnce(std::function<void ()> func, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);

View File

@@ -169,19 +169,12 @@ public:
EVENT(started)
EVENT(stopped)
//! \~english
//! Start event handler with name "handler" of object "object"
//! in separate thread with name "name"
//! and automatically delete it on function finish
//!
//! \~russian
//! \~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
//! Start function "func" in separate thread with name "name"
//! and automatically delete it on function finish
//!
//! \~russian
//! \~english Call lambda-function "func" in separate thread
//! \~russian Вызывает лямбда-функцию "func" в отдельном потоке
static void runOnce(std::function<void()> func, const PIString & name = PIString());
//! \handlers
@@ -190,72 +183,30 @@ public:
//! \fn bool start(int timer_delay = -1)
//! \~english Start thread
//! \~russian Запускает поток
//! \~\details
//! \~english
//! Start execution of \a run() in internal loop with
//! "timer_delay" delay in milliseconds. If "timer_delay" <= 0
//! there is no delay in loop. Thread also exec external function
//! set by \a setSlot() if it`s not null
//! \return \c false if thread already started or can`t start thread
//! \~russian
//! \fn bool startOnce()
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~\details
//! \~english
//! Start execution of \a run() once. Thread also exec
//! external function set by \a setSlot() if it`s not null
//! \return \c false if thread already started or can`t start thread
//! \~russian
//! \fn bool startOnce(ThreadFunc func)
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~\details
//! \~english
//! Overloaded function. Set external function "func" before start
//! \return \c false if thread already started or can`t start thread
//! \~russian
//! \fn void stop(bool wait = false)
//! \~english Stop thread
//! \~russian Останавливает поток
//! \~\details
//! \~english
//! Stop execution of thread and wait for it finish
//! if "wait" is \c true. This function can block for infinite
//! time if "wait" is \c true and any of thread function is
//! busy forever
//! \~russian
//! \fn void terminate()
//! \~english Strongly stop thread
//! \~russian Жестко останавливает поток
//! \~\details
//! \~english
//! Stop execution of thread immediately
//! \~russian
//! \fn bool waitForStart(int timeout_msecs = -1)
//! \~english Wait for thread start
//! \~russian Ожидает старта потока
//! \~\details
//! \~english
//! This function block until thread start for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c false if timeout is exceeded
//! \~russian
//! \fn bool waitForFinish(int timeout_msecs = -1)
//! \~english Wait for thread finish
//! \~russian Ожидает завершения потока
//! \~\details
//! \~english
//! This function block until thread finish for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c false if timeout is exceeded
//! \~russian
//! \fn void lock()
//! \~english Lock internal mutex

View File

@@ -55,13 +55,18 @@ PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
//! \~\details
//! \~english
//! If \a notifyOnce() has been called before, then returns immediately.
//! If \a notifyOnce() has been called before, then returns immediately.\n
//! If \a notifyOnce() has been called "n" times, then returns immediately "n" times,
//! but only if wait in one thread.
//! but only if wait in one thread.\n
//! If many threads waiting, then if \a notifyOnce() has been called "n" times,
//! all threads total returns "n" times in random sequence.
//! all threads total returns "n" times in undefined sequence.
//!
//! \~russian
//! Если ранее был вызван \a notifyOnce(), то возвращает управление немедленно.\n
//! Если ранее был вызван \a notifyOnce() "n" раз, то возвращает управление немедленно "n" раз,
//! но только если ожидать одним потоком.\n
//! Если ожидают несколько потоков, и \a notifyOnce() был вызван "n" раз,
//! то все потоки суммарно вернут управление "n" раз в неопределенной последовательности.
//!
void PIThreadNotifier::wait() {
m.lock();
@@ -73,10 +78,12 @@ void PIThreadNotifier::wait() {
//! \~\details
//! \~english
//! If many threads waiting, then notify randomly one.
//! If many threads waiting, then notify randomly one.\n
//! If call this "n" times, then notify any waiting threads totally "n" times.
//!
//! \~russian
//! Если ожидают несколько потоков, то уведомляет один случайный.\n
//! Если вызвать "n" раз, то все ожидающие потоки уведомятся суммарно "n" раз.
void PIThreadNotifier::notifyOnce() {
m.lock();
cnt++;