merged AI doc, some new pages

This commit is contained in:
2026-03-12 14:46:57 +03:00
parent 07ae277f9e
commit ed13838237
206 changed files with 14088 additions and 5152 deletions

View File

@@ -1,12 +1,11 @@
/*! \file piblockingqueue.h
* \ingroup Thread
* \~\brief
* \~english Queue with blocking
* \~russian Блокирующая очередь
*/
//! \~\file piblockingqueue.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Blocking queue template
//! \~russian Шаблон блокирующей очереди
/*
PIP - Platform Independent Primitives
Blocking queue template
Stephan Fomenko
This program is free software: you can redistribute it and/or modify
@@ -29,16 +28,19 @@
#include "piconditionvar.h"
#include "piqueue.h"
/**
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
* wait for space to become available in the queue when storing an element.
*/
//! \~\ingroup Thread
//! \~\brief
//! \~english Thread-safe queue that supports blocking operations - waits for space when storing and waits for element when retrieving.
//! \~russian Потокобезопасная очередь с поддержкой блокирующих операций - ожидает место при добавлении и ожидает элемент при получении.
template<typename T>
class PIBlockingQueue: private PIQueue<T> {
public:
/**
* \brief Constructor
*/
//! \~\brief
//! \~english Constructs queue with capacity \a capacity.
//! \~russian Создает очередь с емкостью \a capacity.
//! \~\details
//! \~english Passed condition variables become owned by the queue and are deleted with it.
//! \~russian Переданные переменные условия переходят во владение очереди и удаляются вместе с ней.
explicit inline PIBlockingQueue(size_t capacity = SIZE_MAX,
PIConditionVariable * cond_var_add = new PIConditionVariable(),
PIConditionVariable * cond_var_rem = new PIConditionVariable())
@@ -46,9 +48,8 @@ public:
, cond_var_rem(cond_var_rem)
, max_size(capacity) {}
/**
* \brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue.
*/
//! \~english Constructs queue from snapshot of \a other without synchronizing access to the source deque.
//! \~russian Создает очередь из снимка \a other без синхронизации доступа к исходной очереди.
explicit inline PIBlockingQueue(const PIDeque<T> & other)
: cond_var_add(new PIConditionVariable())
, cond_var_rem(new PIConditionVariable()) {
@@ -58,9 +59,8 @@ public:
mutex.unlock();
}
/**
* \brief Thread-safe copy constructor. Initialize queue with copy of other queue elements.
*/
//! \~english Constructs queue by copying another blocking queue while locking both queues.
//! \~russian Создает очередь копированием другой блокирующей очереди с блокировкой обеих очередей.
inline PIBlockingQueue(PIBlockingQueue<T> & other): cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
other.mutex.lock();
mutex.lock();
@@ -70,16 +70,16 @@ public:
other.mutex.unlock();
}
//! \~english Destroys queue and owned condition variables.
//! \~russian Уничтожает очередь и принадлежащие ей переменные условия.
~PIBlockingQueue() {
delete cond_var_add;
delete cond_var_rem;
}
/**
* \brief Inserts the specified element into this queue, waiting if necessary for space to become available.
*
* @param v the element to add
*/
//! \~english Appends \a v, waiting indefinitely until space becomes available when the queue is full.
//! \~russian Добавляет \a v в конец, ожидая без ограничения по времени появления свободного места при заполненной очереди.
PIBlockingQueue<T> & put(const T & v) {
mutex.lock();
cond_var_rem->wait(mutex, [&]() { return PIDeque<T>::size() < max_size; });
@@ -89,16 +89,18 @@ public:
return *this;
}
//! \~english Alias for \a put().
//! \~russian Псевдоним для \a put().
PIBlockingQueue<T> & enqueue(const T & v) { return put(v); }
/**
* \brief Inserts the specified element at the end of this queue if it is possible to do so immediately without
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
*
* @param v the element to add
* @param timeout the timeout waiting for inserting if que is full, if timeout is null, then returns immediately
* @return true if the element was added to this queue, else false
*/
//! \~\brief
//! \~english Tries to append \a v.
//! \~russian Пытается добавить \a v в конец очереди.
//! \~\details
//! \~english
//! With null \a timeout this method checks capacity once and returns immediately.
//! \~russian
//! При пустом \a timeout метод однократно проверяет емкость и возвращается сразу.
bool offer(const T & v, PISystemTime timeout = {}) {
bool isOk;
mutex.lock();
@@ -112,11 +114,9 @@ public:
return isOk;
}
/**
* \brief Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
*
* @return the head of this queue
*/
//! \~english Removes and returns the front element, waiting indefinitely until one becomes available.
//! \~russian Удаляет и возвращает элемент из начала очереди, ожидая его появления без ограничения по времени.
T take() {
T t;
mutex.lock();
@@ -127,18 +127,21 @@ public:
return t;
}
//! \~english Alias for \a take().
//! \~russian Псевдоним для \a take().
T dequeue() { return take(); }
/**
* \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
* element to become available.
*
* @param timeout how long to wait before giving up
* @param defaultVal value, which returns if the specified waiting time elapses before an element is available
* @param isOk flag, which indicates result of method execution. It will be set to false if timeout, or true if
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
//! \~\brief
//! \~english Tries to remove and return the front element.
//! \~russian Пытается удалить и вернуть элемент из начала очереди.
//! \~\details
//! \~english
//! With null \a timeout this method checks once and returns \a defaultVal immediately if the queue is empty.
//! If \a isOk is not null, it is set to \c true on successful retrieval.
//! \~russian
//! При пустом \a timeout метод проверяет очередь один раз и сразу возвращает \a defaultVal, если очередь пуста.
//! \Если \a isOk не равен null, он получает значение \c true при успешном извлечении.
T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) {
T t = defaultVal;
bool isNotEmpty;
@@ -154,12 +157,15 @@ public:
return t;
}
/**
* \brief Returns the number of elements that this queue can ideally (in the absence of memory or resource
* constraints) contains. This is always equal to the initial capacity of this queue less the current size of this queue.
*
* @return the capacity
*/
//! \~\brief
//! \~english Returns configured capacity limit.
//! \~russian Возвращает настроенный предел емкости.
//! \~\details
//! \~english
//! For the default unbounded queue this value is \c SIZE_MAX.
//! \~russian
//! Для очереди без ограничения по умолчанию это значение равно \c SIZE_MAX.
size_t capacity() {
size_t c;
mutex.lock();
@@ -168,12 +174,8 @@ public:
return c;
}
/**
* \brief Returns the number of additional elements that this queue can ideally (in the absence of memory or resource
* constraints) accept. This is always equal to the initial capacity of this queue less the current size of this queue.
*
* @return the remaining capacity
*/
//! \~english Returns how many more elements can be inserted without blocking at the moment of the call.
//! \~russian Возвращает, сколько элементов еще можно вставить без блокировки в момент вызова.
size_t remainingCapacity() {
mutex.lock();
size_t c = max_size - PIDeque<T>::size();
@@ -181,9 +183,8 @@ public:
return c;
}
/**
* \brief Returns the number of elements in this collection.
*/
//! \~english Returns current number of queued elements.
//! \~russian Возвращает текущее количество элементов в очереди.
size_t size() {
mutex.lock();
size_t s = PIDeque<T>::size();
@@ -191,9 +192,9 @@ public:
return s;
}
/**
* \brief Removes all available elements from this queue and adds them to other given queue.
*/
//! \~english Moves up to \a maxCount currently available elements into deque \a other without waiting.
//! \~russian Перемещает до \a maxCount доступных в данный момент элементов в деку \a other без ожидания.
size_t drainTo(PIDeque<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock();
size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount);
@@ -203,9 +204,14 @@ public:
return count;
}
/**
* \brief Removes all available elements from this queue and adds them to other given queue.
*/
//! \~\brief
//! \~english Moves up to \a maxCount currently available elements into blocking queue \a other without waiting.
//! \~russian Перемещает до \a maxCount доступных в данный момент элементов в блокирующую очередь \a other без ожидания.
//! \~\details
//! \~english
//! The actual count is also limited by the remaining capacity of \a other.
//! \~russian
//! Фактическое количество также ограничено оставшейся емкостью \a other.
size_t drainTo(PIBlockingQueue<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock();
other.mutex.lock();

View File

@@ -1,26 +1,25 @@
/*! \file piconditionvar.h
* \ingroup Thread
* \~\brief
* \~english Conditional variable
* \~russian Conditional variable
*/
//! \~\file piconditionvar.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Condition variable for waiting and notification between threads
//! \~russian Переменная условия для ожидания и уведомления между потоками
/*
PIP - Platform Independent Primitives
PIP - Platform Independent Primitives
Condition variable for waiting and notification between threads
Stephan Fomenko
Stephan Fomenko
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 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.
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/>.
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 PICONDITIONVAR_H
@@ -29,92 +28,145 @@
#include "pimutex.h"
#include "pisystemtime.h"
/**
* \brief A condition variable is an object able to block the calling thread until notified to resume.
*
* It uses a PIMutex to lock the thread when one of its wait functions is called. The thread remains
* blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object.
*/
//! \~\ingroup Thread
//! \~\brief
//! \~english Condition variable used together with external %PIMutex.
//! \~russian Переменная условия, используемая вместе с внешним %PIMutex.
class PIP_EXPORT PIConditionVariable {
public:
NO_COPY_CLASS(PIConditionVariable);
//! \~english Constructs condition variable.
//! \~russian Создает переменную условия.
explicit PIConditionVariable();
//! \~english Destroys condition variable.
//! \~russian Уничтожает переменную условия.
virtual ~PIConditionVariable();
/**
* \brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function
* does nothing. If more than one, it is unspecified which of the threads is selected.
*/
//! \~english Wakes one waiting thread, if any.
//! \~russian Пробуждает один ожидающий поток, если он есть.
void notifyOne();
/**
* \brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does
* nothing.
*/
//! \~english Wakes all threads currently waiting on this variable.
//! \~russian Пробуждает все потоки, ожидающие на этой переменной.
void notifyAll();
/**
* \brief see wait(PIMutex &, const std::function<bool()>&)
*/
//! \~english Waits until notification, temporarily releasing \a lk while blocked.
//! \~russian Ожидает уведомления, временно освобождая \a lk на время блокировки.
virtual void wait(PIMutex & lk);
/**
* \brief Wait until notified
*
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* until notified.
*
* At the moment of blocking the thread, the function automatically calls lk.unlock() (PIMutex::unlock()),
* allowing other locked threads to continue.
*
* Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIMutex::lock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex
* locking may block again the thread before returning).
*
* Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
* member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
* being called. Therefore, users of this function shall ensure their condition for resumption is met.
*
* If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
* the thread when it becomes true (which is specially useful to check against spurious wake-up calls).
*
* @param lk lock object used by method wait for data protection
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
* as a bool. This is called repeatedly until it evaluates to true.
*/
//! \~\brief
//! \~english Waits until \a condition becomes true, rechecking it after each wakeup while \a lk is locked.
//! \~russian Ожидает, пока \a condition не станет истинным, повторно проверяя его после каждого пробуждения при заблокированном \a lk.
//! \~\details
//! \~english
//! The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
//! until notified.
//!
//! At the moment of blocking the thread, the function automatically calls lk.unlock() (PIMutex::unlock()),
//! allowing other locked threads to continue.
//!
//! Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIMutex::lock()),
//! leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex
//! locking may block again the thread before returning).
//!
//! Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
//! member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
//! being called. Therefore, users of this function shall ensure their condition for resumption is met.
//!
//! If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
//! the thread when it becomes true (which is specially useful to check against spurious wake-up calls).
//!
//! \param lk lock object used by method wait for data protection
//! \param condition A callable object or function that takes no arguments and returns a value that can be evaluated
//! as a bool. This is called repeatedly until it evaluates to true.
//!
//! \~russian
//! Выполнение текущего потока (который должен быть заблокирован с помощью \a lk методом PIMutex::lock())
//! приостанавливается до получения уведомления.
//!
//! В момент блокировки потока функция автоматически вызывает lk.unlock() (PIMutex::unlock()),
//! позволяя другим заблокированным потокам продолжить выполнение.
//!
//! После получения уведомления (явного, от другого потока) функция разблокируется и вызывает
//! lk.lock() (PIMutex::lock()), возвращая lk в то же состояние, в котором он находился при вызове
//! функции. Затем функция завершается (обратите внимание, что эта последняя блокировка мьютекса
//! может снова заблокировать поток перед возвратом).
//!
//! Обычно функция пробуждается при вызове в другом потоке либо notifyOne(), либо notifyAll().
//! Однако некоторые реализации могут создавать ложные пробуждения без вызова любой из этих функций.
//! Поэтому пользователи этой функции должны убедиться, что условие для возобновления выполнено.
//!
//! Если указано condition, функция блокируется только если condition возвращает false,
//! а уведомления могут разблокировать поток только когда оно станет true (что особенно полезно
//! для проверки ложных пробуждений).
//!
//! \param lk объект блокировки, используемый методом wait для защиты данных
//! \param condition вызываемый объект или функция, не принимающая аргументов и возвращающая значение, которое может быть оценено как
//! bool. Вызывается повторно, пока не примет значение true
//!
virtual void wait(PIMutex & lk, const std::function<bool()> & condition);
/**
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
*/
//! \~english Waits for at most \a timeout and returns \c true if awakened before it expires.
//! \~russian Ожидает не дольше \a timeout и возвращает \c true, если пробуждение произошло до его истечения.
virtual bool waitFor(PIMutex & lk, PISystemTime timeout);
/**
* \brief Wait for timeout or until notified
*
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* during timeout, or until notified (if the latter happens first).
*
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
* other locked threads to continue.
*
* Once notified or once timeout has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last
* mutex locking may block again the thread before returning).
*
* Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
* member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
* being called. Therefore, users of this function shall ensure their condition for resumption is met.
*
* If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
* the thread when it becomes true (which is especially useful to check against spurious wake-up calls).
*
* @param lk lock object used by method wait for data protection
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
* as a bool. This is called repeatedly until it evaluates to true.
* @return false if timeout reached or true if wakeup condition is true
*/
//! \brief
//! \~english Waits until \a condition becomes true or \a timeout expires.
//! \~russian Ожидает, пока \a condition не станет истинным или не истечет \a timeout.
//! \~\details
//! \~english
//! The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
//! during timeout, or until notified (if the latter happens first).
//!
//! At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
//! other locked threads to continue.
//!
//! Once notified or once timeout has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
//! leaving lk in the same state as when the function was called. Then the function returns (notice that this last
//! mutex locking may block again the thread before returning).
//!
//! Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to
//! member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions
//! being called. Therefore, users of this function shall ensure their condition for resumption is met.
//!
//! If condition is specified, the function only blocks if condition returns false, and notifications can only unblock
//! the thread when it becomes true (which is especially useful to check against spurious wake-up calls).
//!
//! \param lk lock object used by method wait for data protection
//! \param condition A callable object or function that takes no arguments and returns a value that can be evaluated
//! as a bool. This is called repeatedly until it evaluates to true.
//! \return false if timeout reached or true if wakeup condition is true
//!
//! \~russian
//! Выполнение текущего потока (который должен быть заблокирован с помощью lk методом PIMutex::lock())
//! приостанавливается на время timeout, или до получения уведомления (в зависимости от того,
//! что произойдет раньше).
//!
//! В момент блокировки потока функция автоматически вызывает lk.unlock() (PIMutex::unlock()),
//! позволяя другим заблокированным потокам продолжить выполнение.
//!
//! После получения уведомления или истечения таймаута функция разблокируется и вызывает
//! lk.lock() (PIMutex::lock()), возвращая lk в то же состояние, в котором он находился при вызове
//! функции. Затем функция завершается (обратите внимание, что эта последняя блокировка мьютекса
//! может снова заблокировать поток перед возвратом).
//!
//! Обычно функция пробуждается при вызове в другом потоке либо notifyOne(), либо notifyAll().
//! Однако некоторые реализации могут создавать ложные пробуждения без вызова любой из этих функций.
//! Поэтому пользователи этой функции должны убедиться, что условие для возобновления выполнено.
//!
//! Если указано condition, функция блокируется только если condition возвращает false,
//! а уведомления могут разблокировать поток только когда оно станет true (что особенно полезно
//! для проверки ложных пробуждений).
//!
//! \param lk объект блокировки, используемый методом wait для защиты данных
//! \param timeout время ожидания
//! \param condition вызываемый объект или функция, не принимающая аргументов и возвращающая значение, которое может быть оценено как
//! bool. Вызывается повторно, пока не примет значение true
//! \return false если достигнут таймаут, или true если условие пробуждения истинно
//!
virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition);
private:

View File

@@ -1,12 +1,11 @@
/*! \file pigrabberbase.h
* \ingroup Thread
* \~\brief
* \~english Abstract class for create grabbers
* \~russian Базовый класс для создания грабберов
*/
//! \~\file pigrabberbase.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Grabber thread base class
//! \~russian Базовый класс потока-граббера
/*
PIP - Platform Independent Primitives
Abstract class for create grabbers
Grabber thread base class
Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
@@ -30,19 +29,42 @@
#include "pithread.h"
#include "pitime.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Base polling grabber thread with a pending queue, recording virtual methods, and a last-item snapshot.
//! \~russian Базовый поток-граббер с очередью ожидающих элементов, виртуальными методами записи и снимком последнего элемента.
//! \~\details
//! \~english
//! Captured items are appended to the internal queue and also copied into \a last(). The snapshot is independent from the queue.
//! \~russian
//! Захваченные элементы добавляются во внутреннюю очередь и также копируются в \a last(). Этот снимок не зависит от очереди.
template<typename T = PIByteArray>
class PIGrabberBase: public PIThread {
PIOBJECT_SUBCLASS(PIGrabberBase, PIThread);
public:
//! \~english Constructs a closed non-recording grabber.
//! \~russian Создает закрытый граббер без записи.
PIGrabberBase() {
is_opened = false;
is_recording = false;
}
//! \~english Stops the grabber thread and releases recording/open state.
//! \~russian Останавливает поток-граббер и освобождает состояние записи и открытия.
virtual ~PIGrabberBase() { stopGrabber(false); }
//! \~english Returns whether the grabber is currently opened.
//! \~russian Возвращает, открыт ли сейчас граббер.
virtual bool isOpened() const { return is_opened; }
//! \~english Returns whether captured items are currently being recorded.
//! \~russian Возвращает, записываются ли сейчас захваченные элементы.
virtual bool isRecording() const { return is_recording; }
//! \~english Starts recording subsequent captured items if the grabber is opened and recording is not active yet.
//! \~russian Запускает запись последующих захваченных элементов, если граббер открыт и запись еще не активна.
virtual void startRecord(const PIString & filename) {
if (!isOpened()) return;
if (isRecording()) return;
@@ -51,6 +73,9 @@ public:
is_recording = true;
rec_mutex.unlock();
}
//! \~english Stops recording if it is active.
//! \~russian Останавливает запись, если она активна.
virtual void stopRecord() {
if (!isOpened()) return;
if (!isRecording()) return;
@@ -59,6 +84,11 @@ public:
stopRecordInternal();
rec_mutex.unlock();
}
//! \~english Returns a copy of the last successfully captured item. This snapshot is kept separately from the pending queue and is not
//! consumed by \a dequeue().
//! \~russian Возвращает копию последнего успешно захваченного элемента. Этот снимок хранится отдельно от очереди ожидания и не
//! извлекается через \a dequeue().
T last() const {
T ret;
last_mutex.lock();
@@ -66,6 +96,9 @@ public:
last_mutex.unlock();
return ret;
}
//! \~english Returns whether the pending queue is empty.
//! \~russian Возвращает, пуста ли очередь ожидающих элементов.
bool isEmpty() {
bool ret;
que_mutex.lock();
@@ -73,6 +106,9 @@ public:
que_mutex.unlock();
return ret;
}
//! \~english Returns the current number of pending captured items.
//! \~russian Возвращает текущее количество ожидающих захваченных элементов.
int queSize() {
int ret;
que_mutex.lock();
@@ -80,6 +116,10 @@ public:
que_mutex.unlock();
return ret;
}
//! \~english Dequeues and returns the oldest pending captured item. If the queue is empty, returns a default-constructed value.
//! \~russian Извлекает и возвращает самый старый ожидающий захваченный элемент. Если очередь пуста, возвращает значение, созданное
//! конструктором по умолчанию.
T dequeue() {
T ret;
// piCoutObj << "start";
@@ -92,6 +132,10 @@ public:
que_mutex.unlock();
return ret;
}
//! \~english Stops the grabber thread. With \a wait_forever equal to \c false the method waits briefly and may terminate the thread
//! forcibly.
//! \~russian Останавливает поток-граббер. При \a wait_forever равном \c false метод ждет недолго и может принудительно завершить поток.
void stopGrabber(bool wait_forever = true) {
if (isRunning()) {
stop();
@@ -104,12 +148,19 @@ public:
}
}
}
//! \~english Opens the grabber immediately. The thread loop also tries to open it automatically when running in a closed state.
//! \~russian Немедленно открывает граббер. Цикл потока также пытается открыть его автоматически, если поток работает в закрытом
//! состоянии.
bool open() {
bool ret = openInternal();
if (!is_opened && ret) opened();
is_opened = ret;
return ret;
}
//! \~english Closes the grabber and resets the last-item snapshot.
//! \~russian Закрывает граббер и сбрасывает снимок последнего элемента.
void close() {
bool em = is_opened;
closeInternal();
@@ -117,28 +168,78 @@ public:
if (em) closed();
is_opened = false;
}
//! \~english Returns diagnostics collected for captured and recorded items.
//! \~russian Возвращает диагностику для захваченных и записанных элементов.
const PIDiagnostics & diag() const { return diag_; }
//! \~english Clears only the pending queue. The value returned by \a last() is not changed.
//! \~russian Очищает только очередь ожидающих элементов. Значение, возвращаемое \a last(), не изменяется.
void clear() {
que_mutex.lock();
que.clear();
que_mutex.unlock();
}
//! \~english Clears the pending queue and closes the grabber.
//! \~russian Очищает очередь ожидания и закрывает граббер.
void restart() {
clear();
close();
}
//! \events
//! \{
//! \fn void dataReady()
//! \brief
//! \~english Raised after a new item has been captured, queued, and copied into \a last().
//! \~russian Вызывается после захвата нового элемента, его добавления в очередь и копирования в \a last().
EVENT(dataReady);
//! \fn void opened()
//! \brief
//! \~english Raised when \a open() switches the grabber into the opened state.
//! \~russian Вызывается, когда \a open() переводит граббер в открытое состояние.
EVENT(opened);
//! \fn void closed()
//! \brief
//! \~english Raised when \a close() closes a previously opened grabber.
//! \~russian Вызывается, когда \a close() закрывает ранее открытый граббер.
EVENT(closed);
//! \}
protected:
//! \~english Virtual method executed once when the thread starts, before polling begins.
//! \~russian Виртуальный метод, выполняемый один раз при старте потока до начала опроса.
virtual void init() {}
//! \~english Opens the underlying grabber resource.
//! \~russian Открывает базовый ресурс граббера.
virtual bool openInternal() = 0;
//! \~english Closes the underlying grabber resource.
//! \~russian Закрывает базовый ресурс граббера.
virtual void closeInternal() = 0;
//! \~english Polls the next item into \a val. Return \c 0 when a new item was captured, a positive value when no item is ready yet, and
//! a negative value on failure that should close the grabber.
//! \~russian Опрашивает следующий элемент в \a val. Возвращает \c 0, когда новый элемент захвачен, положительное значение, когда
//! элемент еще не готов, и отрицательное значение при ошибке, после которой граббер должен закрыться.
virtual int get(T & val) = 0;
//! \~english Records a captured item when recording mode is active.
//! \~russian Записывает захваченный элемент, когда активен режим записи.
virtual void record(const T & val) {}
//! \~english Virtual method called before the recording flag becomes active.
//! \~russian Виртуальный метод, вызываемый перед активацией флага записи.
virtual void startRecordInternal(const PIString & filename) {}
//! \~english Virtual method called after the recording flag is cleared.
//! \~russian Виртуальный метод, вызываемый после сброса флага записи.
virtual void stopRecordInternal() {}
bool is_opened, is_recording;

View File

@@ -28,7 +28,10 @@
#include "piinit.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Mutex for mutual exclusion between threads.
//! \~russian Мьютекс для взаимоисключения между потоками.
class PIP_EXPORT PIMutex {
public:
NO_COPY_CLASS(PIMutex);
@@ -54,6 +57,8 @@ public:
//! \~russian Пробует заблокировать мьютекс
bool tryLock();
//! \~english Returns native mutex handle used by low-level synchronization code.
//! \~russian Возвращает нативный дескриптор мьютекса для низкоуровневой синхронизации.
void * handle();
private:
@@ -63,7 +68,10 @@ private:
PRIVATE_DECLARATION(PIP_EXPORT)
};
//! \~\ingroup Thread
//! \~\brief
//! \~english Scope guard that locks a %PIMutex in constructor and unlocks it in destructor.
//! \~russian Защитник области видимости, который блокирует %PIMutex в конструкторе и разблокирует в деструкторе.
class PIP_EXPORT PIMutexLocker {
public:
NO_COPY_CLASS(PIMutexLocker);

View File

@@ -1,9 +1,8 @@
/*! \file pipipelinethread.h
* \ingroup Thread
* \~\brief
* \~english Class for create multihread pipeline
* \~russian Класс для создания многопоточного конвейера
*/
//! \~\file pipipelinethread.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Thread-based pipeline for multi-stage data processing
//! \~russian Потоковый конвейер для многоэтапной обработки данных
/*
PIP - Platform Independent Primitives
Class for create multihread pipeline
@@ -31,16 +30,31 @@
#include "pithread.h"
//! \~\ingroup Thread
//! \~english Thread-based pipeline template class for multi-stage data processing
//! \~russian Шаблонный класс потокового конвейера для многоэтапной обработки данных
//! \~\details
//! \~english
//! Pipeline thread template class for processing data through multiple stages in separate threads.
//! \~Each stage processes incoming data and passes it to the next stage via event notification.
//! \~russian
//! Шаблонный класс конвейерного потока для многоэтапной обработки данных в отдельных потоках.
//! Каждый этап обрабатывает входные данные и передает их следующему этапу через event-уведомления.
template<typename Tin, typename Tout>
class PIPipelineThread: public PIThread {
PIOBJECT_SUBCLASS(PIPipelineThread, PIThread);
public:
//! \~english Constructs pipeline thread
//! \~russian Создает конвейерный поток
PIPipelineThread() {
cnt = 0;
max_size = 0;
wait_next_pipe = false;
}
//! \~english Stops the stage thread and may terminate it forcibly if it does not finish in time.
//! \~russian Останавливает поток стадии и может принудительно завершить его, если он не завершится вовремя.
~PIPipelineThread() {
stop();
cv.notifyAll();
@@ -49,11 +63,26 @@ public:
terminate();
}
}
//! \~english Connects to next pipeline stage via event notification
//! \~russian Подключает к следующему этапу конвейера через event-уведомления
template<typename T>
void connectTo(PIPipelineThread<Tout, T> * next) {
CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue);
}
EVENT3(calculated, const Tout &, v, bool, wait, bool *, overload);
//! \~\handlers
//! \~\{
//! \~english Event handler for data enqueue
//! \~russian Обработчик события добавления данных в очередь
//! \~\details
//! \~english
//! For bounded queues, \a wait decides whether to block until space is available or to drop the item immediately.
//! \~If \a overload is not null, it is set to \c true when the item is rejected because the queue is full.
//! \~russian
//! Для ограниченных очередей \a wait определяет, ждать ли освобождения места или сразу отбросить элемент.
//! \~Если \a overload не равен null, он получает значение \c true, когда элемент отклонен из-за переполнения очереди.
EVENT_HANDLER3(void, enqueue, const Tin &, v, bool, wait, bool *, overload) {
mutex.lock();
// piCoutObj << "enque" << overload;
@@ -72,9 +101,40 @@ public:
}
mutex.unlock();
}
//! \~\}
//! \~\events
//! \~\{
//! \~\fn void calculated(const Tout & v, bool wait, bool * overload)
//! \~\brief
//! \~english Emitted when processing result is ready
//! \~russian Генерируется когда результат обработки готов
//! \~\details
//! \~english Raised after \a calc() succeeds.
//! \~russian Вызывается после успешного завершения \a calc().
//! \~\note
//! \~english The \a wait flag is propagated to a downstream stage and does not affect this stage's own queue.
//! \~russian Флаг \a wait передается следующей стадии и не влияет на собственную очередь этой стадии.
EVENT3(calculated, const Tout &, v, bool, wait, bool *, overload);
//! \}
//! \~english Enqueue data for processing
//! \~russian Добавляет данные в очередь на обработку
void enqueue(const Tin & v, bool wait = false) { enqueue(v, wait, nullptr); }
//! \~english Returns pointer to counter
//! \~russian Возвращает указатель на счетчик
const ullong * counterPtr() const { return &cnt; }
//! \~english Returns items processed counter
//! \~russian Возвращает количество обработанных элементов
ullong counter() const { return cnt; }
//! \~english Returns whether the input queue is empty.
//! \~russian Возвращает, пуста ли входная очередь.
bool isEmpty() {
bool ret;
mutex.lock();
@@ -82,6 +142,9 @@ public:
mutex.unlock();
return ret;
}
//! \~english Returns the current input queue size.
//! \~russian Возвращает текущий размер входной очереди.
int queSize() {
int ret;
mutex.lock();
@@ -89,6 +152,9 @@ public:
mutex.unlock();
return ret;
}
//! \~english Clear input queue
//! \~russian Очищает входную очередь
void clear() {
mutex.lock();
mutex_wait.lock();
@@ -97,6 +163,12 @@ public:
mutex_wait.unlock();
mutex.unlock();
}
//! \~english Stops calculation and waits for thread finish
//! \~russian Останавливает вычисления и ожидает завершения потока
//! \~\note
//! \~english If the stage does not stop within \a wait_delay, it may be terminated forcibly.
//! \~russian Если стадия не остановится за \a wait_delay, она может быть принудительно завершена.
void stopCalc(int wait_delay = 100) {
if (isRunning()) {
stop();
@@ -108,6 +180,13 @@ public:
}
}
}
//! \~english Returns a copy of the last successfully calculated output.
//! \~russian Возвращает копию последнего успешно вычисленного выхода.
//! \~\note
//! \~english This snapshot is separate from the input queue.
//! \~russian Этот снимок хранится отдельно от входной очереди.
Tout getLast() {
Tout ret;
mutex_last.lock();
@@ -116,8 +195,19 @@ public:
return ret;
}
//! \~english Returns the configured input queue limit.
//! \~russian Возвращает настроенный предел входной очереди.
//! \~\note
//! \~english Value \c 0 means the queue is unbounded.
//! \~russian Значение \c 0 означает, что очередь не ограничена.
uint maxQueSize() { return max_size; }
//! \~english Sets the input queue limit.
//! \~russian Устанавливает предел входной очереди.
//! \~\note
//! \~english Value \c 0 removes the limit. If the queue already exceeds the new limit, it is resized immediately.
//! \~russian Значение \c 0 снимает ограничение. Если очередь уже превышает новый предел, она немедленно приводится к нему.
void setMaxQueSize(uint count) {
mutex.lock();
max_size = count;
@@ -125,16 +215,37 @@ public:
mutex.unlock();
}
//! \~english Returns if waiting for next pipeline stage
//! \~russian Возвращает ожидает ли следующий этап конвейера
bool isWaitNextPipe() { return wait_next_pipe; }
//! \~english Sets whether to wait for next pipeline stage
//! \~russian Устанавливает флаг ожидания следующего этапа конвейера
//! \~\details
//! \~english Sets whether the \a calculated() signal requests waiting in the downstream stage.
//! \~russian Устанавливает, должен ли сигнал \a calculated() запрашивать ожидание на следующей стадии.
//! \~\note
//! \~english This flag only affects downstream propagation and does not change how this stage accepts input.
//! \~russian Этот флаг влияет только на передачу вниз по конвейеру и не меняет правила приема входа этой стадией.
void setWaitNextPipe(bool wait) { wait_next_pipe = wait; }
protected:
//! \~english Calculates one output from queued input \a v.
//! \~russian Вычисляет один выход из очередного входного элемента \a v.
//! \~\note
//! \~english Leave \a ok equal to \c true to publish the result, or set it to \c false to drop this input without forwarding.
//! \~russian Оставьте \a ok равным \c true, чтобы опубликовать результат, или установите \a ok в \c false, чтобы отбросить этот вход
//! без пересылки дальше.
virtual Tout calc(Tin & v, bool & ok) = 0;
//! \~english Maximum queue size (0 means unlimited)
//! \~russian Максимальный размер очереди (0 означает без ограничений)
uint max_size;
private:
void begin() override { cnt = 0; }
void run() override {
mutex.lock();
while (in.isEmpty()) {
@@ -161,6 +272,7 @@ private:
}
// piCoutObj << "run ok";
}
PIMutex mutex, mutex_wait;
PIConditionVariable cv, cv_wait;
PIMutex mutex_last;

View File

@@ -1,13 +1,12 @@
/*! \file piprotectedvariable.h
* \ingroup Thread
* \~\brief
* \~english Thread-safe variable
* \~russian Потокобезопасная переменная
*/
//! \~\file piprotectedvariable.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Thread-safe variable
//! \~russian Потокобезопасная переменная
/*
PIP - Platform Independent Primitives
Thread-safe variable
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
Ivan Pelipenko peri4ko@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
@@ -28,22 +27,36 @@
#include "pimutex.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Thread-safe variable template class
//! \~russian Шаблонный класс потокобезопасной переменной
template<typename T>
class PIP_EXPORT PIProtectedVariable {
public:
//! \~english
//! \~russian
//! \~\brief
//! \~english Pointer-like wrapper returned by \a getRef() while the protected value remains locked.
//! \~russian Указателеподобная обертка, возвращаемая \a getRef(), пока защищенное значение остается заблокированным.
class PIP_EXPORT Pointer {
friend class PIProtectedVariable<T>;
public:
//! \~english Copies wrapper state for access to the same protected value.
//! \~russian Копирует состояние обертки для доступа к тому же защищенному значению.
Pointer(const Pointer & v): pv(v.pv), counter(v.counter + 1) {}
//! \~english Destroys wrapper and releases the mutex when it owns the original lock.
//! \~russian Уничтожает обертку и освобождает мьютекс, когда она владеет исходной блокировкой.
~Pointer() {
if (counter == 0) pv.mutex.unlock();
}
//! \~english Returns pointer access to the protected value.
//! \~russian Возвращает указательный доступ к защищенному значению.
T * operator->() { return &pv.var; }
//! \~english Returns reference access to the protected value.
//! \~russian Возвращает ссылочный доступ к защищенному значению.
T & operator*() { return pv.var; }
private:
@@ -54,29 +67,29 @@ public:
int counter = 0;
};
//! \~english Sets value to \"v\"
//! \~russian Устанавливает значение как \"v\"
//! \~english Replaces the protected value with \a v.
//! \~russian Заменяет защищенное значение на \a v.
void set(T v) {
PIMutexLocker _ml(mutex);
var = std::move(v);
}
//! \~english Lock mutex and returns reference wrapper of value. Unlock on variable destructor.
//! \~russian Блокирует мьютекс и возвращает класс-обертку на значение. Разблокирует в деструкторе переменной.
//! \~english Locks the value and returns wrapper-based access to it.
//! \~russian Блокирует значение и возвращает обертку для доступа к нему.
Pointer getRef() {
mutex.lock();
return Pointer(*this);
}
//! \~english Returns copy of value
//! \~russian Возвращает копию значения
//! \~english Returns a copy of the protected value.
//! \~russian Возвращает копию защищенного значения.
T get() const {
PIMutexLocker _ml(mutex);
return var;
}
//! \~english Sets value to \"v\"
//! \~russian Устанавливает значение как \"v\"
//! \~english Replaces the protected value with \a v.
//! \~russian Заменяет защищенное значение на \a v.
PIProtectedVariable<T> & operator=(T v) {
set(std::move(v));
return *this;
@@ -89,4 +102,4 @@ private:
};
#endif
#endif // PIPROTECTEDVARIABLE_H

View File

@@ -1,13 +1,13 @@
/*! \file pireadwritelock.h
* \ingroup Read/Write lock
* \ingroup Thread
* \~\brief
* \~english Read/Write lock
* \~russian Блокировка чтения/записи
* \~english Read-write lock with multiple readers or one writer
* \~russian Блокировка чтения-записи с несколькими читателями или одним писателем
*/
/*
PIP - Platform Independent Primitives
PIReadWriteLock, PIReadLocker, PIWriteLocker
Ivan Pelipenko peri4ko@yandex.ru
PIReadWriteLock, PIReadLocker, PIWriteLocker
Ivan Pelipenko peri4ko@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
@@ -28,7 +28,10 @@
#include "piconditionvar.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Synchronization primitive that allows concurrent readers and exclusive writer access.
//! \~russian Примитив синхронизации, допускающий одновременных читателей и эксклюзивный доступ писателя.
class PIP_EXPORT PIReadWriteLock {
public:
NO_COPY_CLASS(PIReadWriteLock)
@@ -42,37 +45,37 @@ public:
~PIReadWriteLock();
//! \~english Lock for write. If already locked for write or read, than wait until all locks released.
//! \~russian Заблокировать на запись. Если уже заблокировано на запись или чтение, то ждёт освобождения блокировок.
//! \~english Acquires writer access, waiting until there are no active readers or writer.
//! \~russian Захватывает доступ на запись, ожидая отсутствия активных читателей и писателя.
void lockWrite();
//! \~english Try to lock for write. Returns if operation was successfull.
//! \~russian Пробует заблокировать на запись. Возвращает успех операции.
//! \~english Tries to acquire writer access without waiting.
//! \~russian Пытается захватить доступ на запись без ожидания.
bool tryLockWrite();
//! \~english Try to lock for write for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует заблокировать на запись в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
//! \~english Tries to acquire writer access within \a timeout.
//! \~russian Пытается захватить доступ на запись в пределах \a timeout.
bool tryLockWrite(PISystemTime timeout);
//! \~english Release lock for write.
//! \~russian Освобождает блокировку на запись.
//! \~english Releases writer access and wakes waiting threads.
//! \~russian Освобождает доступ на запись и пробуждает ожидающие потоки.
void unlockWrite();
//! \~english Lock for read. If already locked for write, than wait until write lock released.
//! \~russian Заблокировать на чтение. Если уже заблокировано на запись, то ждёт освобождения записывающей блокировки.
//! \~english Acquires one reader slot, waiting while writer access is active.
//! \~russian Захватывает одно место читателя, ожидая пока активен доступ на запись.
void lockRead();
//! \~english Try to lock for read. Returns if operation was successfull.
//! \~russian Пробует заблокировать на чтение. Возвращает успех операции.
//! \~english Tries to acquire reader access without waiting.
//! \~russian Пытается захватить доступ на чтение без ожидания.
bool tryLockRead();
//! \~english Try to lock for read for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует заблокировать на чтение в течении \"timeout\". Возвращает успех операции (не истек ли тайм-аут).
//! \~english Tries to acquire reader access within \a timeout.
//! \~russian Пытается захватить доступ на чтение в пределах \a timeout.
bool tryLockRead(PISystemTime timeout);
//! \~english Release lock for read.
//! \~russian Освобождает блокировку на чтение.
//! \~english Releases one reader slot and wakes waiting threads.
//! \~russian Освобождает одно место читателя и пробуждает ожидающие потоки.
void unlockRead();
private:
@@ -82,7 +85,10 @@ private:
PIConditionVariable var;
};
//! \~\ingroup Thread
//! \~\brief
//! \~english Scope guard that acquires reader access in constructor and releases it in destructor.
//! \~russian Защитник области видимости, который захватывает доступ на чтение в конструкторе и освобождает его в деструкторе.
class PIP_EXPORT PIReadLocker {
public:
NO_COPY_CLASS(PIReadLocker);
@@ -104,7 +110,10 @@ private:
bool cond = true;
};
//! \~\ingroup Thread
//! \~\brief
//! \~english Scope guard that acquires writer access in constructor and releases it in destructor.
//! \~russian Защитник области видимости, который захватывает доступ на запись в конструкторе и освобождает его в деструкторе.
class PIP_EXPORT PIWriteLocker {
public:
NO_COPY_CLASS(PIWriteLocker);
@@ -127,4 +136,4 @@ private:
};
#endif
#endif // PIREADWRITELOCK_H

View File

@@ -1,13 +1,13 @@
/*! \file pisemaphore.h
* \ingroup Semaphore
* \ingroup Thread
* \~\brief
* \~english Basic semaphore
* \~russian Простой семафор
* \~english Counting semaphore for shared resources
* \~russian Счетный семафор для общих ресурсов
*/
/*
PIP - Platform Independent Primitives
PISemaphore, PISemaphoreLocker
Ivan Pelipenko peri4ko@yandex.ru
PISemaphore, PISemaphoreLocker
Ivan Pelipenko peri4ko@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
@@ -28,7 +28,10 @@
#include "piconditionvar.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Counting semaphore that tracks available resource units.
//! \~russian Счетный семафор, отслеживающий количество доступных единиц ресурса.
class PIP_EXPORT PISemaphore {
public:
NO_COPY_CLASS(PISemaphore)
@@ -42,24 +45,24 @@ public:
~PISemaphore();
//! \~english Acquire \"cnt\" resources. If no available resources, than blocks until they freed.
//! \~russian Захватывает \"cnt\" ресурсов. Если свободных ресурсов недостаточно, то блокирует до их появления.
//! \~english Acquires \a cnt resource units, waiting until enough units become available.
//! \~russian Захватывает \a cnt единиц ресурса, ожидая появления достаточного количества.
void acquire(int cnt = 1);
//! \~english Try to acquire \"cnt\" resources. Returns if operation was successfull.
//! \~russian Пробует захватывает \"cnt\" ресурсов. Возвращает успех захвата.
//! \~english Tries to acquire \a cnt resource units without waiting.
//! \~russian Пытается захватить \a cnt единиц ресурса без ожидания.
bool tryAcquire(int cnt = 1);
//! \~english Try to acquire \"cnt\" resources for \"timeout\". Returns if operation was successfull (timeout has not expired).
//! \~russian Пробует захватывает \"cnt\" ресурсов в течении \"timeout\". Возвращает успех захвата (не истек ли тайм-аут).
//! \~english Tries to acquire \a cnt resource units within \a timeout.
//! \~russian Пытается захватить \a cnt единиц ресурса в пределах \a timeout.
bool tryAcquire(int cnt, PISystemTime timeout);
//! \~english Release \"cnt\" resources.
//! \~russian Освобождает \"cnt\" ресурсов.
//! \~english Releases \a cnt resource units and wakes waiting threads.
//! \~russian Освобождает \a cnt единиц ресурса и пробуждает ожидающие потоки.
void release(int cnt = 1);
//! \~english Returns available resources count.
//! \~russian Возвращает количество свободных ресурсов.
//! \~english Returns the current number of available resource units.
//! \~russian Возвращает текущее количество доступных единиц ресурса.
int available() const;
private:
@@ -68,7 +71,10 @@ private:
PIConditionVariable var;
};
//! \~\ingroup Thread
//! \~\brief
//! \~english Scope guard that acquires semaphore units in constructor and releases them in destructor.
//! \~russian Защитник области видимости, который захватывает единицы семафора в конструкторе и освобождает их в деструкторе.
class PIP_EXPORT PISemaphoreLocker {
public:
NO_COPY_CLASS(PISemaphoreLocker);
@@ -92,4 +98,4 @@ private:
};
#endif
#endif // PISEMAPHORE_H

View File

@@ -1,9 +1,8 @@
/*! \file pispinlock.h
* \ingroup Thread
* \~\brief
* \~english Fast and full-load lock
* \~russian Быстрая блокировка с полной нагрузкой
*/
//! \~\file pispinlock.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Spinlock with busy waiting
//! \~russian Спинлок с активным ожиданием
/*
PIP - Platform Independent Primitives
PISpinlock
@@ -31,6 +30,10 @@
#include <atomic>
//! \~\ingroup Thread
//! \~\brief
//! \~english Lock based on atomic spinning for very short critical sections.
//! \~russian Блокировка на основе атомарного вращения для очень коротких критических секций.
class PIP_EXPORT PISpinlock {
public:
NO_COPY_CLASS(PISpinlock);
@@ -44,27 +47,15 @@ public:
~PISpinlock() {}
//! \~english Lock spinlock
//! \~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
//! Если спинлок свободен, то блокирует его и возвращает управление немедленно.
//! Если спинлок заблокирован, то ожидает разблокировки, затем блокирует и возвращает управление
//! \~english Acquires the spinlock, busy-waiting until it becomes free.
//! \~russian Захватывает спинлок, активно ожидая его освобождения.
void lock() {
while (flag.test_and_set(std::memory_order_acquire))
;
}
//! \~english Unlock spinlock
//! \~russian Разблокирует спинлок
//! \~\details
//! \~english
//! In any case this function returns immediate
//! \~russian
//! В любом случае возвращает управление немедленно
//! \~english Releases the spinlock.
//! \~russian Освобождает спинлок.
void unlock() { flag.clear(std::memory_order_release); }
private:
@@ -72,18 +63,22 @@ private:
};
//! \~\ingroup Thread
//! \~\brief
//! \~english Scope guard that locks a %PISpinlock in constructor and unlocks it in destructor.
//! \~russian Защитник области видимости, который блокирует %PISpinlock в конструкторе и разблокирует его в деструкторе.
class PIP_EXPORT PISpinlockLocker {
public:
NO_COPY_CLASS(PISpinlockLocker);
//! \~english Constructs and lock "s" if "condition" is \c true
//! \~russianСоздает и блокирует спинлок "m" если "condition" \c true
//! \~russian Создает и блокирует спинлок "s" если "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 Разблокирует спинлок "m" если "condition" был \c true
//! \~russian Разблокирует спинлок "s" если "condition" был \c true
~PISpinlockLocker() {
if (cond) spinlock.unlock();
}

View File

@@ -1,9 +1,19 @@
/*! \file pithread.h
* \ingroup Thread
* \~\brief
* \~english Thread class
* \~russian Класс потока
*/
//! \~\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
@@ -66,9 +76,26 @@ public:
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
@@ -78,22 +105,24 @@ class PIP_EXPORT PIThread: public PIObject {
public:
NO_COPY_CLASS(PIThread);
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay"
//! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay"
//! \~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 Contructs thread with external function "func" and main loop delay "loop_delay"
//! \~russian Создает поток с функцией "func" и задержкой цикла "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 Contructs thread with main loop delay "loop_delay"
//! \~russian Создает поток с задержкой цикла "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 Priority of thread
//! \~russian Приоритет потока
//! \~english Thread priority hint.
//! \~russian Подсказка приоритета потока.
enum Priority {
piLowerst /** \~english Lowest \~russian Низший */,
piLow /** \~english Low \~russian Низкий */,
@@ -105,128 +134,126 @@ public:
};
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Starts the thread with the stored callback and loop delay.
//! \~russian Запускает поток с сохраненными обратным вызовом и задержкой цикла.
bool start();
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Stores a new loop delay and starts the thread.
//! \~russian Сохраняет новую задержку цикла и запускает поток.
bool start(PISystemTime loop_delay);
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Stores a callback and starts the thread.
//! \~russian Сохраняет обратный вызов и запускает поток.
bool start(ThreadFunc func);
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Stores a callback and loop delay, then starts the thread.
//! \~russian Сохраняет обратный вызов и задержку цикла, затем запускает поток.
bool start(ThreadFunc func, PISystemTime loop_delay);
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Stores a lambda callback and starts the thread.
//! \~russian Сохраняет лямбда-обратный вызов и запускает поток.
bool start(std::function<void()> func);
//! \~english Start thread
//! \~russian Запускает поток
//! \~english Stores a lambda callback and loop delay, then starts the thread.
//! \~russian Сохраняет лямбда-обратный вызов и задержку цикла, затем запускает поток.
bool start(std::function<void()> func, PISystemTime loop_delay);
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~english Starts a one-shot thread without the repeating loop.
//! \~russian Запускает одноразовый поток без повторяющегося цикла.
bool startOnce();
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~english Stores a callback and starts one-shot execution.
//! \~russian Сохраняет обратный вызов и запускает одноразовое выполнение.
bool startOnce(ThreadFunc func);
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~english Stores a lambda callback and starts one-shot execution.
//! \~russian Сохраняет лямбда-обратный вызов и запускает одноразовое выполнение.
bool startOnce(std::function<void()> func);
EVENT_HANDLER0(void, stop);
EVENT_HANDLER0(void, terminate);
//! \~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 Stop thread and wait for finish. Returns \b false if timeout expired.
//! \~russian Останавливает поток и ожидает завершения. Возвращает \b false если таймаут истек.
//! \~english Requests stop and waits for thread completion. Returns \b false if the timeout expires.
//! \~russian Запрашивает остановку и ожидает завершения потока. Возвращает \b false, если таймаут истек.
bool stopAndWait(PISystemTime timeout = {});
//! \~english Set common data passed to external function
//! \~russian Устанавливает данные, передаваемые в функцию потока
//! \~english Sets the data pointer passed to \a ThreadFunc callbacks.
//! \~russian Устанавливает указатель данных, передаваемый в обратные вызовы \a ThreadFunc.
void setData(void * d) { data_ = d; }
//! \~english Set external function that will be executed after every \a run()
//! \~russian Устанавливает функцию потока, вызываемую после каждого \a run()
//! \~english Sets the callback executed after each \a run() pass.
//! \~russian Устанавливает обратный вызов, выполняемый после каждого прохода \a run().
void setSlot(ThreadFunc func) { ret_func = func; }
//! \~english Set external function that will be executed after every \a run()
//! \~russian Устанавливает функцию потока, вызываемую после каждого \a run()
//! \~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 Set thread priority
//! \~russian Устанавливает приоритет потока
//! \~english Sets the priority hint. If the thread is already running, applies it immediately.
//! \~russian Устанавливает подсказку приоритета. Если поток уже работает, применяет ее немедленно.
void setPriority(PIThread::Priority prior);
//! \~english Returns common data passed to external function
//! \~russian Возвращает данные, передаваемые в функцию потока
//! \~english Returns the data pointer passed to \a ThreadFunc callbacks.
//! \~russian Возвращает указатель данных, передаваемый в обратные вызовы \a ThreadFunc.
void * data() const { return data_; }
//! \~english Return thread priority
//! \~russian Возвращает приоритет потока
//! \~english Returns the configured priority hint.
//! \~russian Возвращает настроенную подсказку приоритета.
PIThread::Priority priority() const { return priority_; }
//! \~english Return if thread is running
//! \~russian Возвращает исполняется ли поток
//! \~english Returns whether the thread is currently running.
//! \~russian Возвращает, выполняется ли поток в данный момент.
bool isRunning() const { return running_; }
//! \~english Return if thread is stopping
//! \~russian Возвращает останавливается ли поток
//! \~english Returns whether stop has been requested and the thread is still finishing.
//! \~russian Возвращает, был ли запрошен останов и поток еще завершает работу.
bool isStopping() const { return running_ && terminating; }
//! \~english Wait for thread start
//! \~russian Ожидает старта потока
//! \~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 Wait for thread finish. Returns \b false if timeout expired.
//! \~russian Ожидает завершения потока. Возвращает \b false если таймаут истек.
//! \~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 Set necessity of lock every \a run() with internal mutex
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
//! \~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; }
EVENT_HANDLER0(void, lock) const { thread_mutex.lock(); }
EVENT_HANDLER0(void, unlock) const { thread_mutex.unlock(); }
//! \~english Returns internal mutex
//! \~russian Возвращает внутренний мьютекс
//! \~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 thread ID
//! \~russian Возвращает ID потока
//! \~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__();
EVENT(started);
EVENT(stopped);
//! \~english Call event handler "handler" of object "object" in separate thread
//! \~russian Вызывает обработчик "handler" объекта "object" в отдельном потоке
//! \~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 Call [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in separate thread
//! \~russian Вызывает [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в отдельном потоке
//! \~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
@@ -234,23 +261,27 @@ public:
//! \fn void stop()
//! \brief
//! \~english Stop thread
//! \~russian Останавливает поток
//! \~english Requests graceful thread shutdown.
//! \~russian Запрашивает корректное завершение потока.
EVENT_HANDLER0(void, stop);
//! \fn void terminate()
//! \brief
//! \~english Strongly stop thread
//! \~russian Жёстко прерывает поток
//! \~english Forces thread termination. Use only as a last resort.
//! \~russian Принудительно прерывает поток. Используйте только как крайнюю меру.
EVENT_HANDLER0(void, terminate);
//! \fn void lock()
//! \brief
//! \~english Lock internal mutex
//! \~russian Блокирует внутренний мьютекс
//! \~english Locks the internal mutex.
//! \~russian Блокирует внутренний мьютекс.
EVENT_HANDLER0(void, lock) const { thread_mutex.lock(); }
//! \fn void unlock()
//! \brief
//! \~english Unlock internal mutex
//! \~russian Разблокирует внутренний мьютекс
//! \~english Unlocks the internal mutex.
//! \~russian Разблокирует внутренний мьютекс.
EVENT_HANDLER0(void, unlock) const { thread_mutex.unlock(); }
//! \}
//! \events
@@ -258,29 +289,31 @@ public:
//! \fn void started()
//! \brief
//! \~english Raise on thread start
//! \~russian Вызывается при старте потока
//! \~english Raised after the thread has started.
//! \~russian Вызывается после запуска потока.
EVENT(started);
//! \fn void stopped()
//! \brief
//! \~english Raise on thread stop
//! \~russian Вызывается при завершении потока
//! \~english Raised when thread shutdown begins.
//! \~russian Вызывается при начале завершения потока.
EVENT(stopped);
//! \}
protected:
static int priority2System(PIThread::Priority p);
//! \~english Function executed once at the start of thread
//! \~russian Метод выполняется один раз при старте потока
//! \~english Virtual method executed once after the system thread starts and before \a started().
//! \~russian Виртуальный метод, выполняемый один раз после запуска системного потока и до \a started().
virtual void begin() { ; }
//! \~english Function executed at every "loop_delay" msecs until thread was stopped
//! \~russian Метод выполняется каждые "loop_delay" миллисекунд
//! \~english Virtual method executed on each loop iteration until stop is requested.
//! \~russian Виртуальный метод, выполняемый на каждой итерации цикла, пока не запрошен останов.
virtual void run() { ; }
//! \~english Function executed once at the end of thread
//! \~russian Метод выполняется один раз при остановке потока
//! \~english Virtual method executed once during thread shutdown after \a stopped().
//! \~russian Виртуальный метод, выполняемый один раз при завершении потока после \a stopped().
virtual void end() { ; }
std::atomic_bool terminating, running_, lockRun;

View File

@@ -1,3 +1,13 @@
/*! \file pithreadmodule.h
* \ingroup Thread
* \~\brief
* \~english Umbrella header for the thread module
* \~russian Зонтичный заголовок модуля потоков
*
* \~\details
* \~english Includes the main public synchronization, worker-thread and timer APIs.
* \~russian Подключает основные публичные API синхронизации, рабочих потоков и таймеров.
*/
/*
PIP - Platform Independent Primitives
Module includes
@@ -34,10 +44,10 @@
//! \~russian \par Общее
//!
//! \~english
//! These files provides thread, timer, blocking and several complex multithreading techniques
//! This module provides thread, timer and synchronization primitives for runtime work.
//!
//! \~russian
//! Эти файлы обеспечивают потоки, таймера, блокировки и несколько сложных многопоточных техник
//! Этот модуль предоставляет потоки, таймеры и примитивы синхронизации для задач времени выполнения.
//!
//! \~\authors
//! \~english

View File

@@ -1,13 +1,12 @@
/*! \file pithreadnotifier.h
* \ingroup Thread
* \~\brief
* \~english Class for simple notify and wait in different threads
* \~russian Класс для простого уведомления и ожидания в различных потоках
*/
//! \~\file pithreadnotifier.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Counting notification helper for coordination between threads
//! \~russian Счетный помощник уведомления для координации между потоками
/*
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@yandex.ru
Ivan Pelipenko peri4ko@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
@@ -29,6 +28,19 @@
#include "piconditionvar.h"
//! \~\ingroup Thread
//! \~\brief
//! \~english Thread notifier class for synchronization between threads.
//! \~russian Класс уведомления потоков для синхронизации между потоками.
//! \~\details
//! \~english
//! Each \a notify() stores one pending wake-up. A later \a wait() or
//! \a waitFor() consumes one stored notification; with multiple waiters the
//! resume order is unspecified.
//! \~russian
//! Каждый вызов \a notify() сохраняет одно ожидающее пробуждение. Последующий
//! \a wait() или \a waitFor() потребляет одно сохраненное уведомление; при
//! нескольких ожидающих потоках порядок возобновления не определен.
class PIP_EXPORT PIThreadNotifier {
public:
PIThreadNotifier();

View File

@@ -1,3 +1,12 @@
//! \~\file pithreadpoolexecutor.h
//! \~\ingroup Thread
//! \brief
//! \~english Thread pool executor
//! \~russian Исполнитель пула потоков
//!
//! \details
//! \~english Executes tasks in a pool of worker threads.
//! \~russian Выполняет задачи в пуле рабочих потоков.
/*
PIP - Platform Independent Primitives
@@ -26,28 +35,55 @@
#include <atomic>
//! \~\ingroup Thread
//! \~\brief
//! \~english Fixed-size pool of worker threads for fire-and-forget tasks.
//! \~russian Фиксированный пул рабочих потоков для задач без ожидания результата.
class PIP_EXPORT PIThreadPoolExecutor {
public:
//! \~english Constructs executor with \a corePoolSize worker threads.
//! \~russian Создает исполнитель с \a corePoolSize рабочими потоками.
explicit PIThreadPoolExecutor(int corePoolSize);
//! \~english Stops worker threads and destroys executor resources.
//! \~russian Останавливает рабочие потоки и уничтожает ресурсы исполнителя.
virtual ~PIThreadPoolExecutor();
//! \brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task
//! cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been
//! reached.
//!
//! \param runnable not empty function for thread pool execution
//! \~\brief
//! \~english Submits \a runnable for asynchronous execution by a worker thread.
//! \~russian Передает \a runnable на асинхронное выполнение рабочим потоком.
//! \details
//! \~english
//! This is a best-effort fire-and-forget call and does not report whether the task was accepted.
//! \After shutdown requests new tasks are ignored.
//! \~russian
//! Это вызов по принципу best-effort без ожидания результата и без сообщения о том, была ли задача принята.
//! \После запроса на завершение новые задачи игнорируются.
void execute(const std::function<void()> & runnable);
//! \~english Requests immediate shutdown and stops worker threads without waiting for queued tasks to finish.
//! \~russian Запрашивает немедленное завершение и останавливает рабочие потоки без ожидания завершения задач в очереди.
void shutdownNow();
//! \brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be
//! accepted. Invocation has no additional effect if already shut down. This method does not wait for previously
//! submitted tasks to complete execution. Use awaitTermination to do that.
//! \~\brief
//! \~english Requests orderly shutdown: new tasks are rejected and workers stop after the current queue is drained.
//! \~russian Запрашивает упорядоченное завершение: новые задачи отклоняются, а рабочие потоки останавливаются после опустошения текущей
//! очереди.
//! \details
//! \~english This method does not wait for worker termination.
//! \~russian Этот метод не ожидает завершения рабочих потоков.
void shutdown();
//! \~english Returns \c true after \a shutdown() or \a shutdownNow() has been requested.
//! \~russian Возвращает \c true после запроса \a shutdown() или \a shutdownNow().
bool isShutdown() const;
//! \~\brief
//! \~english Waits up to \a timeout for all worker threads to finish.
//! \~russian Ожидает до \a timeout завершения всех рабочих потоков.
//! \return
//! \~english \c false if the timeout expires first.
//! \~russian \c false, если таймаут истек раньше.
bool awaitTermination(PISystemTime timeout);
private:

View File

@@ -1,9 +1,8 @@
/*! \file pithreadpoolloop.h
* \ingroup Thread
* \~\brief
* \~english Thread pool loop
* \~russian Пул потоков
*/
//! \~\file pithreadpoolloop.h
//! \~\ingroup Thread
//! \~\brief
//! \~english Parallel loop helper
//! \~russian Вспомогательный класс для параллельного цикла
/*
PIP - Platform Independent Primitives
Thread pool loop
@@ -31,54 +30,44 @@
class PIThread;
//! \~\ingroup Thread
//! \~\brief
//! \~english Helper that runs one integer range across a fixed set of worker threads.
//! \~russian Вспомогательный класс, который выполняет один целочисленный диапазон на фиксированном наборе рабочих потоков.
class PIP_EXPORT PIThreadPoolLoop {
public:
//! \~english
//! Contructs thread pool with threads count "thread_cnt".
//! If "thread_cnt" = -1 then system processors count used
//! \~russian
//! Создает пул из "thread_cnt" потоков. Если "thread_cnt" = -1
//! то используется количество процессоров системы
//! \~english Constructs parallel loop runner with \a thread_cnt worker threads. If \a thread_cnt is less than or equal to zero, the
//! processor count is used.
//! \~russian Создает исполнитель параллельного цикла с \a thread_cnt рабочими потоками. Если \a thread_cnt меньше либо равен нулю,
//! используется количество процессоров.
PIThreadPoolLoop(int thread_cnt = -1);
//! \~english Stops worker threads and destroys the loop runner.
//! \~russian Останавливает рабочие потоки и уничтожает исполнитель цикла.
virtual ~PIThreadPoolLoop();
//! \~english Set threads function to [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "f" with format [ ](int){
//! ... }
//! \~russian Устанавливает функцию потоков на [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "f" в формате [
//! ](int){ ... }
//! \~english Sets the iteration body called once for each index of a started range.
//! \~russian Устанавливает тело итерации, которое вызывается один раз для каждого индекса запущенного диапазона.
void setFunction(std::function<void(int)> f);
//! \~english Wait for all threads stop
//! \~russian Ожидает завершения всех потоков
//! \~english Waits for the current in-flight batch started by \a start().
//! \~russian Ожидает завершения текущего запущенного пакета, начатого через \a start().
void wait();
//! \~english
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! \~russian
//! Начинает исполнение потоков с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
//! \~english Starts asynchronous execution for indices in range [\a index_start, \a index_start + \a index_count).
//! \~russian Запускает асинхронное выполнение для индексов из диапазона [\a index_start, \a index_start + \a index_count).
void start(int index_start, int index_count);
//! \~english
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
//! \~russian
//! Начинает исполнение потоков с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
//! и ожидает завершения
//! \~english Runs the configured iteration body for indices in range [\a index_start, \a index_start + \a index_count) and waits for
//! completion.
//! \~russian Выполняет настроенное тело итерации для индексов из диапазона [\a index_start, \a index_start + \a index_count) и ожидает
//! завершения.
void exec(int index_start, int index_count);
//! \~english
//! Start functions "f" execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
//! \~russian
//! Начинает исполнение потоками функции "f" с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
//! и ожидает завершения
//! \~english Sets iteration body to \a f, runs it for indices in range [\a index_start, \a index_start + \a index_count), and waits for
//! completion.
//! \~russian Устанавливает тело итерации \a f, выполняет его для индексов из диапазона [\a index_start, \a index_start + \a
//! index_count) и ожидает завершения.
void exec(int index_start, int index_count, std::function<void(int)> f);
private:

View File

@@ -1,8 +1,19 @@
/*! \file pitimer.h
* \ingroup Thread
* \~\brief
* \~english Timer
* \~russian Таймер
* \~english Timer object backed by an internal thread
* \~russian Объект таймера, работающий на внутреннем потоке
*
* \~\details
* \~english
* %PITimer uses an internal %PIThread to generate best-effort periodic ticks.
* When queued delivery is enabled, the timer also drains events addressed to it
* as performer through \a maybeCallQueuedEvents() on the main tick.
* \~russian
* %PITimer использует внутренний %PIThread для генерации периодических тиков
* с практической, но не строго гарантированной точностью. Когда включена
* отложенная доставка, таймер также обрабатывает события, адресованные ему как
* исполнителю, через \a maybeCallQueuedEvents() на основном тике.
*/
/*
PIP - Platform Independent Primitives
@@ -33,54 +44,71 @@
class PIThread;
//! \~\ingroup Thread
//! \~\brief
//! \~english Periodic timer that emits ticks from an internal worker thread.
//! \~russian Периодический таймер, который выдает тики из внутреннего рабочего потока.
//! \~\details
//! \~english
//! The main tick uses delimiter value 1. Additional frequency delimiters can
//! request extra callbacks every \a n ticks. This class does not promise exact
//! wake-up timing or scheduler fairness.
//! \~russian
//! Основной тик использует значение делителя 1. Дополнительные делители частоты
//! позволяют запрашивать дополнительные вызовы каждые \a n тиков. Этот класс не
//! обещает точное время пробуждения или справедливость планировщика.
class PIP_EXPORT PITimer: public PIObject {
PIOBJECT_SUBCLASS(PITimer, PIObject);
public:
NO_COPY_CLASS(PITimer);
//! \~english Constructs timer
//! \~russian Создает таймер
//! \~english Constructs a timer without a tick callback.
//! \~russian Создает таймер без обратного вызова тика.
explicit PITimer();
//! \~english Constructs timer with method void(int)
//! \~russian Создает таймер с функцией void(int)
//! \~english Constructs a timer with a callback that receives the delimiter value.
//! \~russian Создает таймер с обратным вызовом, принимающим значение делителя.
explicit PITimer(std::function<void(int)> func);
//! \~english Constructs timer with method void()
//! \~russian Создает таймер с функцией void()
//! \~english Constructs a timer with a callback that ignores the delimiter value.
//! \~russian Создает таймер с обратным вызовом, игнорирующим значение делителя.
explicit PITimer(std::function<void()> func);
//! \~english Destroys the timer and stops its internal worker thread.
//! \~russian Уничтожает таймер и останавливает его внутренний рабочий поток.
virtual ~PITimer();
//! \~english Returns timer loop delay
//! \~russian Возвращает задержку цикла таймера
//! \~english Returns the configured base interval between main ticks.
//! \~russian Возвращает настроенный базовый интервал между основными тиками.
PISystemTime interval() const;
//! \~english Set timer loop delay
//! \~russian Установить интервал таймера
//! \~english Sets the base interval. If the timer is running, restarts it with the new value.
//! \~russian Устанавливает базовый интервал. Если таймер запущен, перезапускает его с новым значением.
void setInterval(PISystemTime interval);
//! \~english Returns if timer is started
//! \~russian Возвращает работает ли таймер
//! \~english Returns whether the timer thread is currently running.
//! \~russian Возвращает, работает ли сейчас поток таймера.
bool isRunning() const;
//! \~english Return if timer is stopping
//! \~russian Возвращает останавливается ли таймер
//! \~english Returns whether stop has been requested and shutdown is still in progress.
//! \~russian Возвращает, был ли запрошен останов и идет ли еще завершение.
bool isStopping() const;
//! \~english Wait for timer stop
//! \~russian Ожидает остановки таймера
//! \~english Waits until the timer finishes. Returns \b false if the timeout expires first.
//! \~russian Ожидает завершения таймера. Возвращает \b false, если таймаут истек раньше.
bool waitForFinish(PISystemTime timeout = {});
//! \~english Start timer with "interval" loop delay
//! \~russian Запустить таймер с интервалом "interval"
//! \~english Sets the base interval and starts the timer.
//! \~russian Устанавливает базовый интервал и запускает таймер.
bool start(PISystemTime interval);
//! \~english Start timer with "interval" loop delay and tick function "func"
//! \~russian Запустить таймер с интервалом "interval" и вызываевымым методом "func"
//! \~english Sets the base interval and tick callback, then starts the timer.
//! \~russian Устанавливает базовый интервал и обратный вызов тика, затем запускает таймер.
bool start(PISystemTime interval, std::function<void()> func);
//! \~english Deprecated overload of \a start() that accepts milliseconds.
//! \~russian Устаревшая перегрузка \a start(), принимающая миллисекунды.
bool start(double interval_ms) DEPRECATEDM("use start(PISystemTime)") { return start(PISystemTime::fromMilliseconds(interval_ms)); }
EVENT_HANDLER0(bool, start);
@@ -88,50 +116,52 @@ public:
EVENT_HANDLER0(void, stop);
//! \~english Stop timer and wait for finish.
//! \~russian Останавливает таймер и ожидает завершения.
//! \~english Deprecated overload of \a stopAndWait() that accepts milliseconds.
//! \~russian Устаревшая перегрузка \a stopAndWait(), принимающая миллисекунды.
void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); }
//! \~english Stop timer and wait for finish.
//! \~russian Останавливает таймер и ожидает завершения.
//! \~english Requests stop and waits for the worker thread to finish.
//! \~russian Запрашивает остановку и ожидает завершения рабочего потока.
void stopAndWait(PISystemTime timeout = {});
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
//! \~english Sets a tick callback that ignores the delimiter value.
//! \~russian Устанавливает обратный вызов тика, игнорирующий значение делителя.
void setSlot(std::function<void()> func) {
ret_func = [func](int) { func(); };
}
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
//! \~english Sets a tick callback that receives the current delimiter value.
//! \~russian Устанавливает обратный вызов тика, принимающий текущее значение делителя.
void setSlot(std::function<void(int)> func) { ret_func = func; }
//! \~english Enables locking of the internal mutex around tick processing.
//! \~russian Включает блокировку внутреннего мьютекса вокруг обработки тиков.
void needLockRun(bool need) { lockRun = need; }
EVENT_HANDLER0(void, lock) { mutex_.lock(); }
EVENT_HANDLER0(void, unlock) { mutex_.unlock(); }
//! \~english Returns if timer should exec \a maybeCallQueuedEvents() at every tick. By default \b true
//! \~russian Возвращает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик. По умолчанию \b true
//! \~english Returns whether the timer drains queued delivery for itself as performer on each main tick. By default \b true.
//! \~russian Возвращает, должен ли таймер обрабатывать отложенную доставку для себя как исполнителя на каждом основном тике. По умолчанию \b true.
bool isCallQueuedEvents() const { return callEvents; }
//! \~english Set timer exec \a maybeCallQueuedEvents() at every tick
//! \~russian Установает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик
//! \~english Enables or disables queued-delivery draining through \a maybeCallQueuedEvents() on each main tick.
//! \~russian Включает или отключает обработку отложенной доставки через \a maybeCallQueuedEvents() на каждом основном тике.
void setCallQueuedEvents(bool yes) { callEvents = yes; }
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
//! \~english Adds a frequency delimiter that invokes \a func every \a delim main ticks.
//! \~russian Добавляет делитель частоты, который вызывает \a func каждые \a delim основных тиков.
void addDelimiter(int delim, std::function<void(int)> func = nullptr);
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
//! \~english Adds a delimiter with a callback that ignores the delimiter value.
//! \~russian Добавляет делитель с обратным вызовом, игнорирующим значение делителя.
void addDelimiter(int delim, std::function<void()> func);
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
//! \~english Adds a delimiter with a pointer-based callback signature.
//! \~russian Добавляет делитель с сигнатурой обратного вызова, принимающей указатель.
void addDelimiter(int delim, std::function<void(void *)> slot);
//! \~english Remove all frequency delimiters "delim"
//! \~russian Удаляет все делители частоты "delim"
//! \~english Removes all delimiters with value \a delim.
//! \~russian Удаляет все делители со значением \a delim.
void removeDelimiter(int delim);
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
@@ -143,37 +173,47 @@ public:
//! \fn bool start()
//! \brief
//! \~english Start timer with \a interval() loop delay
//! \~russian Запустить таймер с интервалом \a interval()
//! \~english Starts the timer with the current \a interval().
//! \~russian Запускает таймер с текущим значением \a interval().
//! \fn bool restart()
//! \brief
//! \~english Stop and start timer with \a interval() loop delay
//! \~russian Остановить и запустить таймер с интервалом \a interval()
//! \~english Stops the timer, then starts it again with the current \a interval().
//! \~russian Останавливает таймер, затем снова запускает его с текущим значением \a interval().
//! \fn bool stop()
//! \brief
//! \~english Stop timer (don`t wait for finish)
//! \~russian Остановить таймер (не дожидается остановки)
//! \~english Requests stop and wakes the timer thread, but does not wait for completion.
//! \~russian Запрашивает остановку и пробуждает поток таймера, но не ожидает завершения.
//! \fn void clearDelimiters()
//! \brief
//! \~english Remove all frequency delimiters
//! \~russian Удаляет все делители частоты
//! \fn void lock()
//! \brief
//! \~english Locks the internal timer mutex.
//! \~russian Блокирует внутренний мьютекс таймера.
//! \fn void unlock()
//! \brief
//! \~english Unlocks the internal timer mutex.
//! \~russian Разблокирует внутренний мьютекс таймера.
//! \}
//! \events
//! \{
//! \fn void tickEvent(int delimiter)
//! \brief
//! \~english Raise on timer tick
//! \~russian Вызывается каждый тик таймера
//! \~english Raised on each timer tick and on configured delimiter ticks.
//! \~russian Вызывается на каждом тике таймера и на настроенных тиках делителей.
//! \~\details
//! \~english
//! "delimiter" is frequency delimiter, 1 for main loop.
//! "delimiter" is the frequency delimiter, 1 for the main loop.
//! \~russian
//! "delimiter" - делитель частоты, 1 для основного цикла
//! "delimiter" - делитель частоты, 1 для основного цикла.
//! \}
@@ -196,7 +236,8 @@ protected:
void adjustTimes();
void execTick();
//! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing
//! \~english Virtual tick method. The main loop passes delimiter 1, additional delimiters pass their own value.
//! \~russian Виртуальный метод тика. Основной цикл передает делитель 1, дополнительные делители передают свое значение.
virtual void tick(int delimiter) {}
PIThread * thread = nullptr;