version 4.0.0_alpha
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread PITimer API no longer pass void* PIPeer, PIConnection improved stability on reinit and exit PISystemTime new methods pisd now exit without hanging
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
#define PIBLOCKINGQUEUE_H
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "pideque.h"
|
||||
#include "piqueue.h"
|
||||
|
||||
/**
|
||||
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
|
||||
@@ -96,16 +96,16 @@ public:
|
||||
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
|
||||
*
|
||||
* @param v the element to add
|
||||
* @param timeoutMs the timeout waiting for inserting if que is full, if timeout = 0, then returns immediately
|
||||
* @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
|
||||
*/
|
||||
bool offer(const T & v, int timeoutMs = 0) {
|
||||
bool offer(const T & v, PISystemTime timeout = {}) {
|
||||
bool isOk;
|
||||
mutex.lock();
|
||||
if (timeoutMs == 0)
|
||||
if (timeout.isNull())
|
||||
isOk = PIDeque<T>::size() < max_size;
|
||||
else
|
||||
isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; });
|
||||
isOk = cond_var_rem->waitFor(mutex, timeout, [&]() { return PIDeque<T>::size() < max_size; });
|
||||
if (isOk) PIDeque<T>::push_back(v);
|
||||
mutex.unlock();
|
||||
if (isOk) cond_var_add->notifyOne();
|
||||
@@ -133,20 +133,20 @@ public:
|
||||
* \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 timeoutMs how long to wait before giving up, in milliseconds
|
||||
* @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
|
||||
*/
|
||||
T poll(int timeoutMs = 0, const T & defaultVal = T(), bool * isOk = nullptr) {
|
||||
T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) {
|
||||
T t = defaultVal;
|
||||
bool isNotEmpty;
|
||||
mutex.lock();
|
||||
if (timeoutMs == 0)
|
||||
if (timeout.isNull())
|
||||
isNotEmpty = !PIDeque<T>::isEmpty();
|
||||
else
|
||||
isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
isNotEmpty = cond_var_add->waitFor(mutex, timeout, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
if (isNotEmpty) t = PIDeque<T>::take_front();
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
#ifdef WINDOWS
|
||||
# include <synchapi.h>
|
||||
# include <winbase.h>
|
||||
@@ -105,19 +103,18 @@ void PIConditionVariable::wait(PIMutex & lk, const std::function<bool()> & condi
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) {
|
||||
bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout) {
|
||||
bool isNotTimeout;
|
||||
#if defined(WINDOWS)
|
||||
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
|
||||
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeout.toMilliseconds()) != 0;
|
||||
#elif defined(FREERTOS)
|
||||
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
|
||||
isNotTimeout = (uxBits & 1) != 0;
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeout.toMilliseconds() / portTICK_PERIOD_MS);
|
||||
isNotTimeout = (uxBits & 1) != 0;
|
||||
#else
|
||||
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||
timespec expire_ts;
|
||||
PISystemTime st = PISystemTime::current(true);
|
||||
st.addMilliseconds(timeoutMs);
|
||||
st.toTimespec(&expire_ts);
|
||||
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0;
|
||||
#endif
|
||||
@@ -125,14 +122,13 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) {
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition) {
|
||||
bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition) {
|
||||
bool isCondition;
|
||||
#if defined(WINDOWS) || defined(FREERTOS)
|
||||
PITimeMeasurer measurer;
|
||||
#else
|
||||
PISystemTime st = PISystemTime::current(true) + timeout;
|
||||
timespec expire_ts;
|
||||
PISystemTime st = PISystemTime::current(true);
|
||||
st.addMilliseconds(timeoutMs);
|
||||
st.toTimespec(&expire_ts);
|
||||
#endif
|
||||
#ifdef FREERTOS
|
||||
@@ -143,12 +139,16 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::functi
|
||||
if (isCondition) break;
|
||||
bool isTimeout;
|
||||
#if defined(WINDOWS)
|
||||
isTimeout =
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0;
|
||||
isTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle,
|
||||
(PCRITICAL_SECTION)lk.handle(),
|
||||
timeout.toMilliseconds() - (int)measurer.elapsed_m()) == 0;
|
||||
#elif defined(FREERTOS)
|
||||
EventBits_t uxBits;
|
||||
uxBits =
|
||||
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
||||
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle,
|
||||
1,
|
||||
pdTRUE,
|
||||
pdTRUE,
|
||||
(timeout.toMilliseconds() - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
||||
isTimeout = (uxBits & 1) == 0;
|
||||
#else
|
||||
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0;
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#ifndef PICONDITIONVAR_H
|
||||
#define PICONDITIONVAR_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pimutex.h"
|
||||
#include "pisystemtime.h"
|
||||
|
||||
|
||||
/**
|
||||
@@ -87,18 +88,18 @@ public:
|
||||
/**
|
||||
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
|
||||
*/
|
||||
virtual bool waitFor(PIMutex & lk, int timeoutMs);
|
||||
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 timeoutMs, or until notified (if the latter happens first).
|
||||
* 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 timeoutMs has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
|
||||
* 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).
|
||||
*
|
||||
@@ -114,7 +115,7 @@ public:
|
||||
* as a bool. This is called repeatedly until it evaluates to true.
|
||||
* @return false if timeout reached or true if wakeup condition is true
|
||||
*/
|
||||
virtual bool waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition);
|
||||
virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition);
|
||||
|
||||
private:
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "pidiagnostics.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
template<typename T = PIByteArray>
|
||||
|
||||
@@ -535,33 +535,33 @@ PRIVATE_DEFINITION_START(PIThread)
|
||||
PRIVATE_DEFINITION_END(PIThread)
|
||||
|
||||
|
||||
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int loop_delay): PIObject() {
|
||||
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, PISystemTime loop_delay): PIObject() {
|
||||
PIINTROSPECTION_THREAD_NEW(this);
|
||||
data_ = data;
|
||||
ret_func = func;
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
delay_ = loop_delay;
|
||||
if (startNow) start(loop_delay);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIThread::PIThread(std::function<void()> func, bool startNow, int loop_delay) {
|
||||
PIThread::PIThread(std::function<void()> func, bool startNow, PISystemTime loop_delay) {
|
||||
PIINTROSPECTION_THREAD_NEW(this);
|
||||
ret_func = [func](void *) { func(); };
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
delay_ = loop_delay;
|
||||
if (startNow) start(loop_delay);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIThread::PIThread(bool startNow, int loop_delay): PIObject() {
|
||||
PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() {
|
||||
PIINTROSPECTION_THREAD_NEW(this);
|
||||
terminating = running_ = lockRun = false;
|
||||
priority_ = piNormal;
|
||||
delay_ = loop_delay;
|
||||
if (startNow) start(loop_delay);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
@@ -573,7 +573,7 @@ PIThread::~PIThread() {
|
||||
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
|
||||
// PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
|
||||
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
|
||||
stop(true);
|
||||
stopAndWait();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
@@ -591,15 +591,47 @@ PIThread::~PIThread() {
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(ThreadFunc func, int loop_delay) {
|
||||
ret_func = func;
|
||||
return start(loop_delay);
|
||||
bool PIThread::start() {
|
||||
if (running_) return false;
|
||||
return _startThread((void *)thread_function);
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(std::function<void()> func, int loop_delay) {
|
||||
bool PIThread::start(PISystemTime loop_delay) {
|
||||
delay_ = loop_delay;
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(ThreadFunc func) {
|
||||
ret_func = func;
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(ThreadFunc func, PISystemTime loop_delay) {
|
||||
ret_func = func;
|
||||
delay_ = loop_delay;
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(std::function<void()> func) {
|
||||
ret_func = [func](void *) { func(); };
|
||||
return start(loop_delay);
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(std::function<void()> func, PISystemTime loop_delay) {
|
||||
ret_func = [func](void *) { func(); };
|
||||
delay_ = loop_delay;
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::startOnce() {
|
||||
if (running_) return false;
|
||||
return _startThread((void *)thread_function_once);
|
||||
}
|
||||
|
||||
|
||||
@@ -609,9 +641,15 @@ bool PIThread::startOnce(ThreadFunc func) {
|
||||
}
|
||||
|
||||
|
||||
void PIThread::stopAndWait(int timeout_ms) {
|
||||
bool PIThread::startOnce(std::function<void()> func) {
|
||||
ret_func = [func](void *) { func(); };
|
||||
return startOnce();
|
||||
}
|
||||
|
||||
|
||||
void PIThread::stopAndWait(PISystemTime timeout) {
|
||||
stop();
|
||||
waitForFinish(timeout_ms);
|
||||
waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -621,19 +659,6 @@ void PIThread::stop() {
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(int loop_delay) {
|
||||
if (running_) return false;
|
||||
delay_ = loop_delay;
|
||||
return _startThread((void *)thread_function);
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::startOnce() {
|
||||
if (running_) return false;
|
||||
return _startThread((void *)thread_function_once);
|
||||
}
|
||||
|
||||
|
||||
void PIThread::terminate() {
|
||||
piCoutObj << "Warning, terminate!";
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
|
||||
@@ -766,7 +791,7 @@ void PIThread::setPriority(PIThread::Priority prior) {
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
|
||||
policy_ = 0;
|
||||
int policy_ = 0;
|
||||
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
|
||||
pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
|
||||
PRIVATE->sparam.
|
||||
@@ -785,16 +810,6 @@ void PIThread::setPriority(PIThread::Priority prior) {
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::waitForStart(PISystemTime timeout) {
|
||||
return waitForStart(timeout.toMilliseconds());
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::waitForFinish(PISystemTime timeout) {
|
||||
return waitForFinish(timeout.toMilliseconds());
|
||||
}
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
bool isExists(HANDLE hThread) {
|
||||
// errorClear();
|
||||
@@ -808,11 +823,12 @@ bool isExists(HANDLE hThread) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
|
||||
bool PIThread::waitForFinish(PISystemTime timeout) {
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
|
||||
// timeout_msecs;
|
||||
if (!running_) return true;
|
||||
if (timeout_msecs < 0) {
|
||||
if (timeout.isNull()) {
|
||||
while (running_) {
|
||||
piMinSleep();
|
||||
#ifdef WINDOWS
|
||||
@@ -825,7 +841,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
return true;
|
||||
}
|
||||
tmf_.reset();
|
||||
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
|
||||
while (running_ && tmf_.elapsed() < timeout) {
|
||||
piMinSleep();
|
||||
#ifdef WINDOWS
|
||||
if (!isExists(PRIVATE->thread)) {
|
||||
@@ -834,21 +850,21 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return tmf_.elapsed_m() < timeout_msecs;
|
||||
return tmf_.elapsed() < timeout;
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::waitForStart(int timeout_msecs) {
|
||||
bool PIThread::waitForStart(PISystemTime timeout) {
|
||||
if (running_) return true;
|
||||
if (timeout_msecs < 0) {
|
||||
if (timeout.isNull()) {
|
||||
while (!running_)
|
||||
piMinSleep();
|
||||
return true;
|
||||
}
|
||||
tms_.reset();
|
||||
while (!running_ && tms_.elapsed_m() < timeout_msecs)
|
||||
while (!running_ && tms_.elapsed() < timeout)
|
||||
piMinSleep();
|
||||
return tms_.elapsed_m() < timeout_msecs;
|
||||
return tms_.elapsed() < timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -940,11 +956,11 @@ void PIThread::__thread_func__() {
|
||||
_runThread();
|
||||
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
|
||||
PIINTROSPECTION_THREAD_WAIT(this);
|
||||
if (delay_ > 0) {
|
||||
if (delay_.isNotNull()) {
|
||||
tmr_.reset();
|
||||
double sl(0.);
|
||||
while (1) {
|
||||
sl = piMind(delay_ - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
|
||||
sl = piMind(delay_.toMilliseconds() - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
|
||||
if (terminating) break;
|
||||
if (sl <= 0.) break;
|
||||
piMSleep(sl);
|
||||
|
||||
@@ -79,15 +79,15 @@ public:
|
||||
|
||||
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay"
|
||||
//! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay"
|
||||
PIThread(void * data, ThreadFunc func, bool startNow = false, int loop_delay = -1);
|
||||
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"
|
||||
PIThread(std::function<void()> func, bool startNow = false, int loop_delay = -1);
|
||||
PIThread(std::function<void()> func, bool startNow = false, PISystemTime loop_delay = {});
|
||||
|
||||
//! \~english Contructs thread with main loop delay "loop_delay"
|
||||
//! \~russian Создает поток с задержкой цикла "loop_delay"
|
||||
PIThread(bool startNow = false, int loop_delay = -1);
|
||||
PIThread(bool startNow = false, PISystemTime loop_delay = {});
|
||||
|
||||
virtual ~PIThread();
|
||||
|
||||
@@ -103,27 +103,55 @@ public:
|
||||
piHighest /** \~english Highest \~russian Высший */
|
||||
};
|
||||
|
||||
EVENT_HANDLER0(bool, start) { return start(-1); }
|
||||
EVENT_HANDLER1(bool, start, int, loop_delay);
|
||||
bool start(PISystemTime loop_delay) { return start(loop_delay.toMilliseconds()); }
|
||||
bool start(ThreadFunc func) { return start(func, -1); }
|
||||
bool start(ThreadFunc func, int loop_delay);
|
||||
bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
||||
bool start(std::function<void()> func) { return start(func, -1); }
|
||||
bool start(std::function<void()> func, int loop_delay);
|
||||
bool start(std::function<void()> func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); }
|
||||
EVENT_HANDLER0(bool, startOnce);
|
||||
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start();
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(PISystemTime loop_delay);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(ThreadFunc func);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(ThreadFunc func, PISystemTime loop_delay);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(std::function<void()> func);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(std::function<void()> func, PISystemTime loop_delay);
|
||||
|
||||
//! \~english Start thread without internal loop
|
||||
//! \~russian Запускает поток без внутреннего цикла
|
||||
bool startOnce();
|
||||
|
||||
//! \~english Start thread without internal loop
|
||||
//! \~russian Запускает поток без внутреннего цикла
|
||||
bool startOnce(ThreadFunc func);
|
||||
|
||||
//! \~english Start thread without internal loop
|
||||
//! \~russian Запускает поток без внутреннего цикла
|
||||
bool startOnce(std::function<void()> func);
|
||||
|
||||
EVENT_HANDLER0(void, stop);
|
||||
EVENT_HANDLER0(void, terminate);
|
||||
|
||||
//! \~english Stop thread and wait for finish.
|
||||
//! \~russian Останавливает поток и ожидает завершения.
|
||||
void stopAndWait(int timeout_ms = -1);
|
||||
void stopAndWait(int timeout_ms) DEPRECATEDM("use waitForStart(PISystemTime)") {
|
||||
stopAndWait(PISystemTime::fromMilliseconds(timeout_ms));
|
||||
}
|
||||
|
||||
//! \~english Stop thread and wait for finish.
|
||||
//! \~russian Останавливает поток и ожидает завершения.
|
||||
void stopAndWait(PISystemTime timeout) { stopAndWait(timeout.toMilliseconds()); }
|
||||
void stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Set common data passed to external function
|
||||
//! \~russian Устанавливает данные, передаваемые в функцию потока
|
||||
@@ -159,12 +187,19 @@ public:
|
||||
//! \~russian Возвращает останавливается ли поток
|
||||
bool isStopping() const { return running_ && terminating; }
|
||||
|
||||
EVENT_HANDLER0(bool, waitForStart) { return waitForStart(-1); }
|
||||
EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs);
|
||||
bool waitForStart(PISystemTime timeout);
|
||||
EVENT_HANDLER0(bool, waitForFinish) { return waitForFinish(-1); }
|
||||
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
|
||||
bool waitForFinish(PISystemTime timeout);
|
||||
//! \~english Wait for thread start
|
||||
//! \~russian Ожидает старта потока
|
||||
bool waitForStart(PISystemTime timeout = {});
|
||||
bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") {
|
||||
return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs));
|
||||
}
|
||||
|
||||
//! \~english Wait for thread finish
|
||||
//! \~russian Ожидает завершения потока
|
||||
bool waitForFinish(PISystemTime timeout = {});
|
||||
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()
|
||||
@@ -198,21 +233,6 @@ public:
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn bool start(int loop_delay = -1)
|
||||
//! \brief
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
|
||||
//! \fn bool startOnce()
|
||||
//! \brief
|
||||
//! \~english Start thread without internal loop
|
||||
//! \~russian Запускает поток без внутреннего цикла
|
||||
|
||||
//! \fn bool startOnce(ThreadFunc func)
|
||||
//! \brief
|
||||
//! \~english Start thread without internal loop
|
||||
//! \~russian Запускает поток без внутреннего цикла
|
||||
|
||||
//! \fn void stop()
|
||||
//! \brief
|
||||
//! \~english Stop thread
|
||||
@@ -223,16 +243,6 @@ public:
|
||||
//! \~english Strongly stop thread
|
||||
//! \~russian Жёстко прерывает поток
|
||||
|
||||
//! \fn bool waitForStart(int timeout_msecs = -1)
|
||||
//! \brief
|
||||
//! \~english Wait for thread start
|
||||
//! \~russian Ожидает старта потока
|
||||
|
||||
//! \fn bool waitForFinish(int timeout_msecs = -1)
|
||||
//! \brief
|
||||
//! \~english Wait for thread finish
|
||||
//! \~russian Ожидает завершения потока
|
||||
|
||||
//! \fn void lock()
|
||||
//! \brief
|
||||
//! \~english Lock internal mutex
|
||||
@@ -275,7 +285,7 @@ protected:
|
||||
virtual void end() { ; }
|
||||
|
||||
std::atomic_bool terminating, running_, lockRun;
|
||||
int delay_, policy_;
|
||||
PISystemTime delay_;
|
||||
llong tid_ = -1;
|
||||
void * data_ = nullptr;
|
||||
mutable PIMutex thread_mutex;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "pithreadpoolexecutor.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
|
||||
/*! \class PIThreadPoolExecutor
|
||||
* \brief Thread pools address two different problems: they usually provide improved performance when executing large
|
||||
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
|
||||
@@ -29,7 +31,7 @@
|
||||
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) {
|
||||
for (int i = 0; i < corePoolSize; ++i) {
|
||||
PIThread * thread = new PIThread([&, i]() {
|
||||
auto runnable = taskQueue.poll(100, std::function<void()>());
|
||||
auto runnable = taskQueue.poll(100_ms, std::function<void()>());
|
||||
if (runnable) {
|
||||
runnable();
|
||||
}
|
||||
@@ -41,11 +43,11 @@ PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false)
|
||||
}
|
||||
|
||||
|
||||
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
|
||||
bool PIThreadPoolExecutor::awaitTermination(PISystemTime timeout) {
|
||||
PITimeMeasurer measurer;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) {
|
||||
int dif = timeoutMs - (int)measurer.elapsed_m();
|
||||
if (dif < 0) return false;
|
||||
auto dif = timeout - measurer.elapsed();
|
||||
if (dif.isNegative()) return false;
|
||||
if (!threadPool[i]->waitForFinish(dif)) return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define PITHREADPOOLEXECUTOR_H
|
||||
|
||||
#include "piblockingqueue.h"
|
||||
#include "pithread.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -47,7 +48,7 @@ public:
|
||||
|
||||
bool isShutdown() const;
|
||||
|
||||
bool awaitTermination(int timeoutMs);
|
||||
bool awaitTermination(PISystemTime timeout);
|
||||
|
||||
private:
|
||||
std::atomic_bool isShutdown_;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "pithreadpoolloop.h"
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pisysteminfo.h"
|
||||
#include "pithread.h"
|
||||
|
||||
@@ -115,7 +116,7 @@ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
|
||||
PIThreadPoolLoop::~PIThreadPoolLoop() {
|
||||
for (auto * t: threads) {
|
||||
t->stop();
|
||||
if (!t->waitForFinish(100)) t->terminate();
|
||||
if (!t->waitForFinish(100_ms)) t->terminate();
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
#include "pitimer.h"
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals.h"
|
||||
#ifdef PIP_TIMER_RT
|
||||
# include <csignal>
|
||||
#endif
|
||||
#include "piliterals_time.h"
|
||||
#include "pithread.h"
|
||||
|
||||
|
||||
//! \addtogroup Thread
|
||||
@@ -52,22 +49,22 @@
|
||||
//! \~russian \section PITimer_sec1 Варианты уведомления
|
||||
//! \~english
|
||||
//! Notify variants:
|
||||
//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda
|
||||
//! * "slot" - static function with format void func(int delimiter) or [lambda
|
||||
//! expression](https://en.cppreference.com/w/cpp/language/lambda);
|
||||
//! * event - \a tickEvent();
|
||||
//! * virtual function - \a tick().
|
||||
//!
|
||||
//! Lambda should be [ ]( ){ } or [ ](void*){ } format.
|
||||
//! Lambda should be [ ]( ){ } or [ ](int){ } format.
|
||||
//!
|
||||
//! All these variants are equivalent, use most applicable.
|
||||
//! \~russian
|
||||
//! Варианты уведомления:
|
||||
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или
|
||||
//! * "slot" - статический метод в формате void func(int delimiter) или
|
||||
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
|
||||
//! * event - \a tickEvent();
|
||||
//! * виртуальный метод - \a tick().
|
||||
//!
|
||||
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](void*){ }.
|
||||
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](int){ }.
|
||||
//!
|
||||
//! Все варианты аналогичны друг другу, используйте самый удобный.
|
||||
//!
|
||||
@@ -89,10 +86,10 @@
|
||||
//! Пример:
|
||||
//!
|
||||
//! \~\code
|
||||
//! void tfunc(void * , int delim) {
|
||||
//! void tfunc(int delim) {
|
||||
//! piCout << "tick with delimiter" << delim;
|
||||
//! };
|
||||
//! void tfunc4(void * , int delim) {
|
||||
//! void tfunc4(int delim) {
|
||||
//! piCout << "tick4 with delimiter" << delim;
|
||||
//! };
|
||||
//! int main() {
|
||||
@@ -101,8 +98,7 @@
|
||||
//! timer.addDelimiter(4, tfunc4);
|
||||
//! timer.start(50);
|
||||
//! piMSleep(200);
|
||||
//! timer.stop();
|
||||
//! timer.waitForFinish();
|
||||
//! timer.stopAndWait();
|
||||
//! return 0;
|
||||
//! };
|
||||
//! /* Result:
|
||||
@@ -119,596 +115,163 @@
|
||||
//! \}
|
||||
|
||||
|
||||
_PITimerBase::_PITimerBase() {
|
||||
running_ = false;
|
||||
PITimer::PITimer(): PIObject() {
|
||||
initFirst();
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::setInterval(double i) {
|
||||
interval_ = i;
|
||||
PITimer::PITimer(std::function<void(int)> func) {
|
||||
initFirst();
|
||||
ret_func = func;
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(std::function<void()> func) {
|
||||
initFirst();
|
||||
ret_func = [func](int) { func(); };
|
||||
}
|
||||
|
||||
|
||||
PITimer::~PITimer() {
|
||||
stopAndWait();
|
||||
piDeleteSafety(thread);
|
||||
}
|
||||
|
||||
|
||||
PISystemTime PITimer::interval() const {
|
||||
return m_interval;
|
||||
}
|
||||
|
||||
|
||||
void PITimer::setInterval(PISystemTime interval) {
|
||||
if (m_interval == interval) return;
|
||||
m_interval = interval;
|
||||
if (isRunning()) {
|
||||
// piCout << "change interval runtime";
|
||||
stop();
|
||||
stopAndWait();
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerBase::start(double interval_ms) {
|
||||
if (isRunning()) stop();
|
||||
deferred_ = false;
|
||||
setInterval(interval_ms);
|
||||
// piCout << "_PITimerBase::startTimer"<<interval_ms<<"...";
|
||||
running_ = startTimer(interval_ms);
|
||||
return running_;
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::startDeferred(double interval_ms, PIDateTime start_datetime) {
|
||||
if (isRunning()) stop();
|
||||
deferred_ = true;
|
||||
deferred_mode = true;
|
||||
deferred_datetime = start_datetime;
|
||||
setInterval(interval_ms);
|
||||
running_ = startTimer(interval_ms);
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::startDeferred(double interval_ms, double delay_ms) {
|
||||
if (isRunning()) stop();
|
||||
deferred_ = true;
|
||||
deferred_mode = false;
|
||||
deferred_delay = delay_ms;
|
||||
setInterval(interval_ms);
|
||||
running_ = startTimer(interval_ms);
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerBase::stop() {
|
||||
// piCout << GetCurrentThreadId() << "_PITimerBase::stop" << wait << isRunning();
|
||||
if (!isRunning()) return true;
|
||||
// piCout << "_PITimerBase::stopTimer ...";
|
||||
running_ = !stopTimer();
|
||||
return !running_;
|
||||
}
|
||||
|
||||
|
||||
class _PITimerImp_Thread: public _PITimerBase {
|
||||
public:
|
||||
_PITimerImp_Thread();
|
||||
virtual ~_PITimerImp_Thread() { stop(); }
|
||||
|
||||
protected:
|
||||
void prepareStart(double interval_ms);
|
||||
bool threadFunc(); // returns true if repeat is needed
|
||||
int wait_dt, wait_dd, wait_tick;
|
||||
|
||||
private:
|
||||
bool startTimer(double interval_ms) override;
|
||||
bool stopTimer() override;
|
||||
static void threadFuncS(void * d) { ((_PITimerImp_Thread *)d)->threadFunc(); }
|
||||
void adjustTimes();
|
||||
bool smallWait(int ms);
|
||||
|
||||
PIThread thread_;
|
||||
PISystemTime st_time, st_inc, st_wait, st_odt;
|
||||
PIConditionVariable event;
|
||||
};
|
||||
|
||||
|
||||
#ifdef PIP_TIMER_RT
|
||||
struct _PITimerImp_RT_Private_;
|
||||
class _PITimerImp_RT: public _PITimerBase {
|
||||
public:
|
||||
_PITimerImp_RT();
|
||||
virtual ~_PITimerImp_RT();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
bool startTimer(double interval_ms) override;
|
||||
bool stopTimer() override;
|
||||
|
||||
int ti;
|
||||
_PITimerImp_RT_Private_ * priv;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class _PITimerImp_Pool: public _PITimerImp_Thread {
|
||||
public:
|
||||
_PITimerImp_Pool();
|
||||
virtual ~_PITimerImp_Pool() { stop(); }
|
||||
|
||||
private:
|
||||
class Pool: public PIThread {
|
||||
public:
|
||||
static Pool * instance();
|
||||
void add(_PITimerImp_Pool * t);
|
||||
void remove(_PITimerImp_Pool * t);
|
||||
void run() override;
|
||||
PIVector<_PITimerImp_Pool *> timers, to_remove;
|
||||
|
||||
private:
|
||||
explicit Pool();
|
||||
virtual ~Pool();
|
||||
};
|
||||
bool startTimer(double interval_ms) override;
|
||||
bool stopTimer() override;
|
||||
};
|
||||
|
||||
|
||||
_PITimerImp_Thread::_PITimerImp_Thread() {
|
||||
thread_.setName("__S__PITimerImp_Thread::thread"_a);
|
||||
wait_dt = 1000;
|
||||
wait_dd = 2000;
|
||||
wait_tick = 1000;
|
||||
// piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_;
|
||||
// piCout << "new _PITimerImp_Thread";
|
||||
}
|
||||
|
||||
|
||||
void _PITimerImp_Thread::prepareStart(double interval_ms) {
|
||||
if (interval_ms <= 0.) {
|
||||
piCout << "Achtung! Start PITimer with interval <= 0!";
|
||||
piCout << "Achtung! Parent" << parent;
|
||||
assert(interval_ms > 0.);
|
||||
}
|
||||
st_inc = PISystemTime::fromMilliseconds(interval_ms);
|
||||
st_odt = st_inc * 5;
|
||||
if (st_odt.toSeconds() < 1.) st_odt = 1_s;
|
||||
if (deferred_) {
|
||||
if (!deferred_mode) st_time = PISystemTime::current(true) + PISystemTime::fromMilliseconds(deferred_delay);
|
||||
st_time -= st_inc;
|
||||
} else
|
||||
st_time = PISystemTime::current(true) + st_inc;
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Thread::startTimer(double interval_ms) {
|
||||
prepareStart(interval_ms);
|
||||
thread_.setData(this);
|
||||
return thread_.start(threadFuncS);
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Thread::stopTimer() {
|
||||
thread_.stop();
|
||||
event.notifyAll();
|
||||
thread_.waitForFinish();
|
||||
// if (wait)
|
||||
// if (!thread_.waitForFinish(10))
|
||||
// if (thread_.isRunning())
|
||||
// thread_.terminate();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Thread::threadFunc() {
|
||||
if (!running_) return false;
|
||||
if (deferred_) {
|
||||
PISystemTime dwt;
|
||||
int wth(wait_dt);
|
||||
if (deferred_mode) {
|
||||
dwt = deferred_datetime.toSystemTime() - PISystemTime::current();
|
||||
wth = wait_dd;
|
||||
} else
|
||||
dwt = st_time - PISystemTime::current(true);
|
||||
if (wth > 0) {
|
||||
if (dwt.toMilliseconds() > wth + 1.) {
|
||||
smallWait(wth);
|
||||
return false;
|
||||
} else {
|
||||
if (!smallWait(dwt.toMilliseconds())) return false;
|
||||
deferred_ = false;
|
||||
st_time = PISystemTime::current(true);
|
||||
}
|
||||
} else {
|
||||
if (dwt.toMilliseconds() > 0.1) return false;
|
||||
}
|
||||
}
|
||||
st_wait = st_time - PISystemTime::current(true);
|
||||
// piCout << "wait" << this << st_wait;
|
||||
if (st_wait.abs() > st_odt || st_wait.seconds <= -5) {
|
||||
// piCout << &thread_ << "adjust" << "...";
|
||||
adjustTimes();
|
||||
// piCout << &thread_ << "adjust" << "ok";
|
||||
return true;
|
||||
}
|
||||
if (wait_tick > 0) {
|
||||
if (st_wait.toMilliseconds() > wait_tick + 1.) {
|
||||
smallWait(wait_tick);
|
||||
return false;
|
||||
} else {
|
||||
// piCout << &thread_ << "sleep for" << st_wait;
|
||||
if (!smallWait(st_wait.toMilliseconds())) return false;
|
||||
}
|
||||
} else {
|
||||
if (st_wait.toMilliseconds() > 0.1) return false;
|
||||
}
|
||||
st_time += st_inc;
|
||||
if (!parent->isPIObject()) {
|
||||
piCout << "Achtung! PITimer \"parent\" is not PIObject!";
|
||||
return false;
|
||||
}
|
||||
// piCout << &thread_ << "tfunc" << "...";
|
||||
tfunc(parent);
|
||||
// piCout << &thread_ << "tfunc" << "ok";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void _PITimerImp_Thread::adjustTimes() {
|
||||
PISystemTime cst = PISystemTime::current(true);
|
||||
if (st_time < cst) {
|
||||
int rs = (cst - st_time).toSeconds() / st_inc.toSeconds();
|
||||
if (rs >= 100)
|
||||
st_time = cst + st_inc;
|
||||
else {
|
||||
while (st_time < cst)
|
||||
st_time += st_inc;
|
||||
}
|
||||
} else {
|
||||
int rs = (st_time - cst).toSeconds() / st_inc.toSeconds();
|
||||
if (rs >= 100)
|
||||
st_time = cst - st_inc;
|
||||
else {
|
||||
cst += st_inc;
|
||||
while (st_time > cst)
|
||||
st_time -= st_inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Thread::smallWait(int ms) {
|
||||
if (thread_.isStopping()) return false;
|
||||
if (ms > 0) {
|
||||
thread_.mutex().lock();
|
||||
event.waitFor(thread_.mutex(), ms);
|
||||
thread_.mutex().unlock();
|
||||
}
|
||||
return !thread_.isStopping();
|
||||
}
|
||||
|
||||
|
||||
#ifdef PIP_TIMER_RT
|
||||
|
||||
void threadFuncS(sigval sv) {
|
||||
((_PITimerImp_RT *)sv.sival_ptr)->tfunc(((_PITimerImp_RT *)sv.sival_ptr)->parent);
|
||||
}
|
||||
|
||||
struct _PITimerImp_RT_Private_ {
|
||||
itimerspec spec;
|
||||
timer_t tt;
|
||||
sigevent se;
|
||||
};
|
||||
|
||||
_PITimerImp_RT::_PITimerImp_RT() {
|
||||
// piCout << "new _PITimerImp_RT";
|
||||
priv = new _PITimerImp_RT_Private_();
|
||||
priv->tt = 0;
|
||||
ti = -1;
|
||||
memset(&(priv->se), 0, sizeof(priv->se));
|
||||
priv->se.sigev_notify = SIGEV_THREAD;
|
||||
priv->se.sigev_value.sival_ptr = this;
|
||||
priv->se.sigev_notify_function = threadFuncS;
|
||||
priv->se.sigev_notify_attributes = 0;
|
||||
}
|
||||
|
||||
|
||||
_PITimerImp_RT::~_PITimerImp_RT() {
|
||||
stop();
|
||||
delete priv;
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_RT::startTimer(double interval_ms) {
|
||||
int flags(0);
|
||||
priv->spec.it_interval.tv_nsec = ((int)(interval_ms * 1000) % 1000000) * 1000;
|
||||
priv->spec.it_interval.tv_sec = (time_t)(interval_ms / 1000);
|
||||
if (deferred_) {
|
||||
if (deferred_mode) {
|
||||
PISystemTime dtm = deferred_datetime.toSystemTime();
|
||||
priv->spec.it_value.tv_nsec = dtm.nanoseconds;
|
||||
priv->spec.it_value.tv_sec = dtm.seconds;
|
||||
flags = TIMER_ABSTIME;
|
||||
} else {
|
||||
priv->spec.it_value.tv_nsec = ((int)(deferred_delay * 1000) % 1000000) * 1000;
|
||||
priv->spec.it_value.tv_sec = (time_t)(deferred_delay / 1000);
|
||||
}
|
||||
} else {
|
||||
priv->spec.it_value = priv->spec.it_interval;
|
||||
}
|
||||
ti = timer_create(CLOCK_REALTIME, &(priv->se), &(priv->tt));
|
||||
// cout << "***create timer " << msecs << " msecs\n";
|
||||
if (ti == -1) {
|
||||
piCout << "Can`t create RT timer for " << interval_ms << " msecs: " << errorString();
|
||||
return false;
|
||||
}
|
||||
timer_settime(priv->tt, flags, &(priv->spec), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_RT::stopTimer() {
|
||||
if (ti < 0) return true;
|
||||
timer_delete(priv->tt);
|
||||
ti = -1;
|
||||
priv->tt = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
_PITimerImp_Pool::_PITimerImp_Pool(): _PITimerImp_Thread() {
|
||||
wait_dt = wait_dd = wait_tick = 0;
|
||||
// piCout << "new _PITimerImp_Pool";
|
||||
}
|
||||
|
||||
|
||||
_PITimerImp_Pool::Pool::Pool(): PIThread() {
|
||||
setName("__S__PITimerImp_Pool::Pool"_a);
|
||||
needLockRun(true);
|
||||
#ifndef FREERTOS
|
||||
timers.reserve(64);
|
||||
start(PIP_MIN_MSLEEP * 5);
|
||||
#else
|
||||
start(PIP_MIN_MSLEEP);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
_PITimerImp_Pool::Pool::~Pool() {
|
||||
stop();
|
||||
if (!waitForFinish(500)) terminate();
|
||||
unlock();
|
||||
timers.clear();
|
||||
}
|
||||
|
||||
|
||||
_PITimerImp_Pool::Pool * _PITimerImp_Pool::Pool::instance() {
|
||||
static Pool pool;
|
||||
return &pool;
|
||||
}
|
||||
|
||||
|
||||
void _PITimerImp_Pool::Pool::add(_PITimerImp_Pool * t) {
|
||||
// piCout << "add ...";
|
||||
lock();
|
||||
to_remove.removeAll(t);
|
||||
if (!timers.contains(t)) timers << t;
|
||||
unlock();
|
||||
// piCout << "add done";
|
||||
}
|
||||
|
||||
|
||||
void _PITimerImp_Pool::Pool::remove(_PITimerImp_Pool * t) {
|
||||
// piCout << "remove ...";
|
||||
lock();
|
||||
to_remove << t;
|
||||
unlock();
|
||||
// piCout << "remove done";
|
||||
}
|
||||
|
||||
|
||||
void _PITimerImp_Pool::Pool::run() {
|
||||
if (!to_remove.isEmpty()) {
|
||||
piForeach(_PITimerImp_Pool * t, to_remove)
|
||||
timers.removeAll(t);
|
||||
to_remove.clear();
|
||||
}
|
||||
piForeach(_PITimerImp_Pool * t, timers)
|
||||
t->threadFunc();
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Pool::startTimer(double interval_ms) {
|
||||
prepareStart(interval_ms);
|
||||
Pool::instance()->add(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerImp_Pool::stopTimer() {
|
||||
Pool::instance()->remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(): PIObject() {
|
||||
#ifdef FREERTOS
|
||||
imp_mode = PITimer::Thread;
|
||||
#else
|
||||
imp_mode = PITimer::Thread;
|
||||
#endif
|
||||
initFirst();
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(PITimer::TimerImplementation ti): PIObject() {
|
||||
imp_mode = ti;
|
||||
initFirst();
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(TimerEvent slot, void * data, PITimer::TimerImplementation ti): PIObject() {
|
||||
imp_mode = ti;
|
||||
initFirst();
|
||||
data_t = data;
|
||||
ret_func = slot;
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(std::function<void()> slot, PITimer::TimerImplementation ti) {
|
||||
imp_mode = ti;
|
||||
initFirst();
|
||||
ret_func = [slot](void *, int) { slot(); };
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(std::function<void(void *)> slot, void * data, PITimer::TimerImplementation ti) {
|
||||
imp_mode = ti;
|
||||
initFirst();
|
||||
data_t = data;
|
||||
ret_func = [slot](void * d, int) { slot(d); };
|
||||
}
|
||||
|
||||
|
||||
PITimer::~PITimer() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
double PITimer::interval() const {
|
||||
init();
|
||||
return imp->interval_;
|
||||
}
|
||||
|
||||
|
||||
void PITimer::setInterval(double ms) {
|
||||
init();
|
||||
setProperty("interval", ms);
|
||||
imp->setInterval(ms);
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::isRunning() const {
|
||||
init();
|
||||
return imp->running_;
|
||||
return thread->isRunning();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::isStopped() const {
|
||||
init();
|
||||
return !imp->running_;
|
||||
bool PITimer::isStopping() const {
|
||||
return thread->isStopping();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::waitForFinish(PISystemTime timeout) {
|
||||
return thread->waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
void PITimer::initFirst() {
|
||||
lockRun = false;
|
||||
callEvents = true;
|
||||
setProperty("interval", 0.);
|
||||
thread = new PIThread([this] { threadFunc(); });
|
||||
thread->setName("__S__.PITimer.thread");
|
||||
setProperty("interval", PISystemTime());
|
||||
}
|
||||
|
||||
|
||||
void PITimer::init() const {
|
||||
if (imp) return;
|
||||
switch (imp_mode) {
|
||||
case PITimer::Pool: imp = new _PITimerImp_Pool(); break;
|
||||
case PITimer::ThreadRT:
|
||||
#ifdef PIP_TIMER_RT
|
||||
imp = new _PITimerImp_RT();
|
||||
break;
|
||||
#else
|
||||
piCoutObj << "Warning: \"ThreadRT\" is not available at this system! Using \"Thread\".";
|
||||
#endif
|
||||
case PITimer::Thread: imp = new _PITimerImp_Thread(); break;
|
||||
default: piCout << "Fatal: invalid implementation() of" << this << "!"; assert(0);
|
||||
void PITimer::threadFunc() {
|
||||
PISystemTime st_wait = m_time_next - PISystemTime::current(true);
|
||||
// piCout << "wait" << this << st_wait;
|
||||
if (st_wait.abs() > m_interval_x5 || st_wait.seconds <= -5) {
|
||||
// piCout << &thread_ << "adjust" << "...";
|
||||
adjustTimes();
|
||||
// piCout << &thread_ << "adjust" << "ok";
|
||||
return;
|
||||
}
|
||||
if (!imp) return;
|
||||
// piCout << this << "init" << imp;
|
||||
imp->tfunc = tickImpS;
|
||||
imp->parent = const_cast<PITimer *>(this);
|
||||
if (thread->isStopping()) return;
|
||||
if (st_wait.isPositive()) {
|
||||
thread->mutex().lock();
|
||||
event.waitFor(thread->mutex(), st_wait);
|
||||
thread->mutex().unlock();
|
||||
}
|
||||
if (thread->isStopping()) return;
|
||||
m_time_next += m_interval;
|
||||
// piCout << &thread_ << "tfunc" << "...";
|
||||
execTick();
|
||||
}
|
||||
|
||||
|
||||
void PITimer::destroy() {
|
||||
if (!imp) return;
|
||||
// piCout << this << "destroy" << imp;
|
||||
imp->stop();
|
||||
delete imp;
|
||||
imp = 0;
|
||||
void PITimer::adjustTimes() {
|
||||
PISystemTime cst = PISystemTime::current(true);
|
||||
if (m_time_next < cst) {
|
||||
int rs = (cst - m_time_next).toSeconds() / m_interval.toSeconds();
|
||||
if (rs >= 100)
|
||||
m_time_next = cst + m_interval;
|
||||
else {
|
||||
while (m_time_next < cst)
|
||||
m_time_next += m_interval;
|
||||
}
|
||||
} else {
|
||||
int rs = (m_time_next - cst).toSeconds() / m_interval.toSeconds();
|
||||
if (rs >= 100)
|
||||
m_time_next = cst - m_interval;
|
||||
else {
|
||||
cst += m_interval;
|
||||
while (m_time_next > cst)
|
||||
m_time_next -= m_interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PITimer::tickImp() {
|
||||
void PITimer::execTick() {
|
||||
if (!isRunning()) return;
|
||||
if (lockRun) lock();
|
||||
if (ret_func) ret_func(data_t, 1);
|
||||
tick(data_t, 1);
|
||||
tickEvent(data_t, 1);
|
||||
if (ret_func) ret_func(1);
|
||||
tick(1);
|
||||
tickEvent(1);
|
||||
if (callEvents) maybeCallQueuedEvents();
|
||||
piForeach(Delimiter & i, delims) {
|
||||
for (Delimiter & i: delims) {
|
||||
if (i.delim > ++(i.tick)) continue;
|
||||
i.tick = 0;
|
||||
if (i.slot)
|
||||
i.slot(data_t, i.delim);
|
||||
if (i.func)
|
||||
i.func(i.delim);
|
||||
else if (ret_func)
|
||||
ret_func(data_t, i.delim);
|
||||
tick(data_t, i.delim);
|
||||
tickEvent(data_t, i.delim);
|
||||
ret_func(i.delim);
|
||||
tick(i.delim);
|
||||
tickEvent(i.delim);
|
||||
}
|
||||
if (lockRun) unlock();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::start() {
|
||||
init();
|
||||
// piCout << this << "start" << imp;
|
||||
return imp->start();
|
||||
if (isRunning()) return true;
|
||||
m_interval_x5 = m_interval * 5;
|
||||
if (m_interval_x5.toSeconds() < 1.) m_interval_x5 = 1_s;
|
||||
m_time_next = PISystemTime::current(true) + m_interval;
|
||||
if (!thread->start()) return false;
|
||||
return thread->waitForStart();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::start(double interval_ms_d) {
|
||||
init();
|
||||
// piCout << this << "start" << imp << interval_ms_d;
|
||||
setProperty("interval", interval_ms_d);
|
||||
return imp->start(interval_ms_d);
|
||||
bool PITimer::start(PISystemTime interval) {
|
||||
if (isRunning()) stopAndWait();
|
||||
setInterval(interval);
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::start(int interval_ms_i) {
|
||||
return start((double)interval_ms_i);
|
||||
void PITimer::stopAndWait(PISystemTime timeout) {
|
||||
stop();
|
||||
thread->waitForFinish(timeout);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Timer wait "delay_msecs" milliseconds and then normally starts with \a interval() loop delay
|
||||
//! \~russian
|
||||
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом \a interval()
|
||||
void PITimer::startDeferred(double delay_ms) {
|
||||
init();
|
||||
imp->startDeferred(delay_ms);
|
||||
void PITimer::addDelimiter(int delim, std::function<void(int)> func) {
|
||||
delims << Delimiter(func, delim);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Timer wait "delay_msecs" milliseconds and then normally starts with "interval_msecs" loop delay
|
||||
//! \~russian
|
||||
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом "interval_msecs"
|
||||
void PITimer::startDeferred(double interval_ms, double delay_ms) {
|
||||
init();
|
||||
imp->startDeferred(interval_ms, delay_ms);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Timer wait until "start_datetime" and then normally starts with \a interval() loop delay
|
||||
//! \~russian
|
||||
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом \a interval()
|
||||
void PITimer::startDeferred(PIDateTime start_datetime) {
|
||||
startDeferred(imp->interval_, start_datetime);
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Timer wait until "start_datetime" and then normally starts with "interval_msecs" loop delay
|
||||
//! \~russian
|
||||
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом "interval_msecs"
|
||||
void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) {
|
||||
init();
|
||||
imp->startDeferred(interval_ms, start_datetime);
|
||||
}
|
||||
|
||||
|
||||
void PITimer::addDelimiter(int delim, std::function<void(void *)> slot) {
|
||||
delims << Delimiter([slot](void * d, int) { slot(d); }, delim);
|
||||
void PITimer::addDelimiter(int delim, std::function<void()> func) {
|
||||
delims << Delimiter([func](int) { func(); }, delim);
|
||||
}
|
||||
|
||||
|
||||
@@ -722,14 +285,12 @@ void PITimer::removeDelimiter(int delim) {
|
||||
|
||||
|
||||
bool PITimer::restart() {
|
||||
init();
|
||||
imp->stop();
|
||||
return imp->start();
|
||||
stopAndWait();
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PITimer::stop() {
|
||||
init();
|
||||
// piCout << this << "stop" << imp << wait;
|
||||
return imp->stop();
|
||||
void PITimer::stop() {
|
||||
thread->stop();
|
||||
event.notifyAll();
|
||||
}
|
||||
|
||||
@@ -26,50 +26,12 @@
|
||||
#ifndef PITIMER_H
|
||||
#define PITIMER_H
|
||||
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
#include "piconditionvar.h"
|
||||
#include "piobject.h"
|
||||
#include "pisystemtime.h"
|
||||
|
||||
typedef std::function<void(void *, int)> TimerEvent;
|
||||
|
||||
class PITimer;
|
||||
|
||||
class PIP_EXPORT _PITimerBase {
|
||||
friend class PITimer;
|
||||
|
||||
public:
|
||||
_PITimerBase();
|
||||
virtual ~_PITimerBase() {}
|
||||
|
||||
double interval() const { return interval_; }
|
||||
void setInterval(double i);
|
||||
|
||||
bool isRunning() const { return running_; }
|
||||
|
||||
bool isStopped() const { return !running_; }
|
||||
|
||||
bool start() { return start(interval_); }
|
||||
bool start(double interval_ms);
|
||||
void startDeferred(double delay_ms) { startDeferred(interval_, delay_ms); }
|
||||
void startDeferred(double interval_ms, double delay_ms);
|
||||
void startDeferred(PIDateTime start_datetime) { startDeferred(interval_, start_datetime); }
|
||||
void startDeferred(double interval_ms, PIDateTime start_datetime);
|
||||
|
||||
bool stop();
|
||||
|
||||
typedef void (*TickFunc)(PITimer *);
|
||||
TickFunc tfunc = nullptr;
|
||||
PITimer * parent = nullptr;
|
||||
|
||||
protected:
|
||||
virtual bool startTimer(double interval_ms) = 0;
|
||||
virtual bool stopTimer() = 0;
|
||||
|
||||
double interval_ = 1000., deferred_delay = 0.;
|
||||
bool deferred_ = false, deferred_mode = false; // mode: true - date, false - delay
|
||||
std::atomic_bool running_;
|
||||
PIDateTime deferred_datetime;
|
||||
};
|
||||
|
||||
class PIThread;
|
||||
|
||||
class PIP_EXPORT PITimer: public PIObject {
|
||||
PIOBJECT_SUBCLASS(PITimer, PIObject);
|
||||
@@ -77,118 +39,70 @@ class PIP_EXPORT PITimer: public PIObject {
|
||||
public:
|
||||
NO_COPY_CLASS(PITimer);
|
||||
|
||||
//! \~english Constructs timer with PITimer::Thread implementation
|
||||
//! \~russian Создает таймер с реализацией PITimer::Thread
|
||||
//! \~english Constructs timer
|
||||
//! \~russian Создает таймер
|
||||
explicit PITimer();
|
||||
|
||||
//! \~english Timer implementations
|
||||
//! \~russian Реализация таймера
|
||||
enum TimerImplementation {
|
||||
Thread /*!
|
||||
\~english Timer works in his own thread. Intervals are measured by the system time
|
||||
\~russian Таймер работает в собственном потоке. Интервалы измеряются с помощью системного времени
|
||||
*/
|
||||
= 0x01,
|
||||
ThreadRT /*!
|
||||
\~english Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS!
|
||||
\~russian Использовать таймер POSIX с SIGEV_THREAD уведомлением. \attention Не поддерживается на Windows и Mac OS!
|
||||
*/
|
||||
= 0x02,
|
||||
Pool /*!
|
||||
\~english Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and
|
||||
sequentially executes all timers. \attention Use this implementation with care!
|
||||
\~russian Использовать единый TimerPool для всех таймеров с этой реализацией. TimerPool реализован через Thread и
|
||||
последовательно исполняет все таймеры. \attention Осторожнее с этой реализацией!
|
||||
*/
|
||||
= 0x04
|
||||
};
|
||||
//! \~english Constructs timer with method void(int)
|
||||
//! \~russian Создает таймер с функцией void(int)
|
||||
explicit PITimer(std::function<void(int)> func);
|
||||
|
||||
//! \~english Constructs timer with "ti" implementation
|
||||
//! \~russian Создает таймер с реализацией "ti"
|
||||
explicit PITimer(TimerImplementation ti);
|
||||
|
||||
//! \~english Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation
|
||||
//! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti"
|
||||
explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread);
|
||||
|
||||
//! \~english Constructs timer with "slot" slot void(), and "ti" implementation
|
||||
//! \~russian Создает таймер со слотом "slot" и реализацией "ti"
|
||||
explicit PITimer(std::function<void()> slot, TimerImplementation ti = Thread);
|
||||
|
||||
//! \~english Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation
|
||||
//! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti"
|
||||
explicit PITimer(std::function<void(void *)> slot, void * data, TimerImplementation ti = Thread);
|
||||
//! \~english Constructs timer with method void()
|
||||
//! \~russian Создает таймер с функцией void()
|
||||
explicit PITimer(std::function<void()> func);
|
||||
|
||||
virtual ~PITimer();
|
||||
|
||||
//! \~english Returns timer loop delay
|
||||
//! \~russian Возвращает задержку цикла таймера
|
||||
PISystemTime interval() const;
|
||||
|
||||
//! \~english Returns timer implementation
|
||||
//! \~russian Возвращает реализацию таймера
|
||||
PITimer::TimerImplementation implementation() const { return imp_mode; }
|
||||
|
||||
//! \~english Returns timer loop delay in milliseconds
|
||||
//! \~russian Возвращает задержку цикла таймера в миллисекундах
|
||||
double interval() const;
|
||||
|
||||
EVENT_HANDLER1(void, setInterval, double, ms);
|
||||
void setInterval(PISystemTime interval) { setInterval(interval.toMilliseconds()); }
|
||||
//! \~english Set timer loop delay
|
||||
//! \~russian Установить интервал таймера
|
||||
void setInterval(PISystemTime interval);
|
||||
|
||||
//! \~english Returns if timer is started
|
||||
//! \~russian Возвращает работает ли таймер
|
||||
bool isRunning() const;
|
||||
|
||||
//! \~english Returns if timer is not started
|
||||
//! \~russian Возвращает остановлен ли таймер
|
||||
bool isStopped() const;
|
||||
//! \~english Return if timer is stopping
|
||||
//! \~russian Возвращает останавливается ли таймер
|
||||
bool isStopping() const;
|
||||
|
||||
//! \~english Wait for timer stop
|
||||
//! \~russian Ожидает остановки таймера
|
||||
bool waitForFinish(PISystemTime timeout = {});
|
||||
|
||||
//! \fn bool start(PISystemTime interval)
|
||||
//! \brief
|
||||
//! \~english Start timer with "interval" loop delay
|
||||
//! \~russian Запустить таймер с интервалом "interval"
|
||||
bool start(PISystemTime interval);
|
||||
|
||||
bool start(double interval_ms) DEPRECATEDM("use start(PISystemTime)") { return start(PISystemTime::fromMilliseconds(interval_ms)); }
|
||||
EVENT_HANDLER0(bool, start);
|
||||
EVENT_HANDLER1(bool, start, double, interval_ms_d);
|
||||
bool start(int interval_ms_i);
|
||||
bool start(PISystemTime interval) { return start(interval.toMilliseconds()); }
|
||||
|
||||
EVENT_HANDLER0(bool, restart);
|
||||
|
||||
EVENT_HANDLER0(void, stop);
|
||||
|
||||
//! \~english Start timer with \a interval() loop delay after "delay_msecs" delay
|
||||
//! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs"
|
||||
void startDeferred(double delay_ms);
|
||||
//! \~english Stop timer and wait for finish.
|
||||
//! \~russian Останавливает таймер и ожидает завершения.
|
||||
void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); }
|
||||
|
||||
//! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay
|
||||
//! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs"
|
||||
void startDeferred(double interval_ms, double delay_ms);
|
||||
|
||||
//! \~english Start timer with \a interval() loop delay after "start_datetime" date and time
|
||||
//! \~russian Запускает таймер с интервалом \a interval() после наступления "start_datetime"
|
||||
void startDeferred(PIDateTime start_datetime);
|
||||
|
||||
//! \~english Start timer with "interval_msecs" loop delay after "start_datetime" date and time
|
||||
//! \~russian Запускает таймер с интервалом "interval_msecs" после наступления "start_datetime"
|
||||
void startDeferred(double interval_ms, PIDateTime start_datetime);
|
||||
|
||||
EVENT_HANDLER0(bool, stop);
|
||||
|
||||
//! \~english Set custom data
|
||||
//! \~russian Установить данные, передаваемые в метод таймера
|
||||
void setData(void * data_) { data_t = data_; }
|
||||
|
||||
//! \~english Returns common data passed to tick functions
|
||||
//! \~russian Возвращает данные, передаваемые в метод таймера
|
||||
void * data() const { return data_t; }
|
||||
//! \~english Stop timer and wait for finish.
|
||||
//! \~russian Останавливает таймер и ожидает завершения.
|
||||
void stopAndWait(PISystemTime timeout = {});
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(TimerEvent slot) { ret_func = slot; }
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(std::function<void()> slot) {
|
||||
ret_func = [slot](void *, int) { slot(); };
|
||||
void setSlot(std::function<void()> func) {
|
||||
ret_func = [func](int) { func(); };
|
||||
}
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(std::function<void(void *)> slot) {
|
||||
ret_func = [slot](void * d, int) { slot(d); };
|
||||
}
|
||||
void setSlot(std::function<void(int)> func) { ret_func = func; }
|
||||
|
||||
void needLockRun(bool need) { lockRun = need; }
|
||||
EVENT_HANDLER0(void, lock) { mutex_.lock(); }
|
||||
@@ -204,13 +118,11 @@ public:
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
void addDelimiter(int delim, TimerEvent slot = 0) { delims << Delimiter(slot, delim); }
|
||||
void addDelimiter(int delim, std::function<void(int)> func = nullptr);
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
void addDelimiter(int delim, std::function<void()> slot) {
|
||||
delims << Delimiter([slot](void *, int) { slot(); }, delim);
|
||||
}
|
||||
void addDelimiter(int delim, std::function<void()> func);
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
@@ -222,39 +134,15 @@ public:
|
||||
|
||||
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
|
||||
|
||||
EVENT2(tickEvent, void *, data_, int, delimiter);
|
||||
EVENT1(tickEvent, int, delimiter);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
|
||||
//! \fn void setInterval(double ms)
|
||||
//! \brief
|
||||
//! \~english Set timer loop delay in milliseconds
|
||||
//! \~russian Установить интервал таймера "ms" миллисекунд
|
||||
|
||||
//! \fn bool start()
|
||||
//! \brief
|
||||
//! \~english Start timer with \a interval() loop delay
|
||||
//! \~russian Запустить таймер с интервалом \a interval()
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Start execution of timer functions with frequency = 1 / msecs Hz
|
||||
//! \~russian
|
||||
//! Запускает таймер с частотой = 1 / msecs Гц
|
||||
|
||||
//! \fn bool start(double msecs)
|
||||
//! \brief
|
||||
//! \~english Start timer with "msecs" loop delay
|
||||
//! \~russian Запустить таймер с интервалом "msecs"
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! Start execution of timer functions with frequency = 1. / msecs Hz.
|
||||
//! Instead of \a start(int msecs) this function allow start timer
|
||||
//! with frequencies more than 1 kHz
|
||||
//! \~russian
|
||||
//! Запускает таймер с частотой = 1 / msecs Гц. В отличии от
|
||||
//! \a start(int msecs) этот метод позволяет запустить таймер с частотой
|
||||
//! более 1 кГц
|
||||
|
||||
//! \fn bool restart()
|
||||
//! \brief
|
||||
@@ -263,8 +151,8 @@ public:
|
||||
|
||||
//! \fn bool stop()
|
||||
//! \brief
|
||||
//! \~english Stop timer and wait for it finish
|
||||
//! \~russian Остановить таймер и дождаться остановки
|
||||
//! \~english Stop timer (don`t wait for finish)
|
||||
//! \~russian Остановить таймер (не дожидается остановки)
|
||||
|
||||
//! \fn void clearDelimiters()
|
||||
//! \brief
|
||||
@@ -275,16 +163,14 @@ public:
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
//! \fn void tickEvent(void * data, int delimiter)
|
||||
//! \fn void tickEvent(int delimiter)
|
||||
//! \brief
|
||||
//! \~english Raise on timer tick
|
||||
//! \~russian Вызывается каждый тик таймера
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! "data" can be set with function \a setData() or from constructor.
|
||||
//! "delimiter" is frequency delimiter, 1 for main loop.
|
||||
//! \~russian
|
||||
//! "data" устанавливается методом \a setData() или в конструкторе.
|
||||
//! "delimiter" - делитель частоты, 1 для основного цикла
|
||||
|
||||
|
||||
@@ -292,33 +178,33 @@ public:
|
||||
|
||||
protected:
|
||||
struct PIP_EXPORT Delimiter {
|
||||
Delimiter(TimerEvent slot_ = 0, int delim_ = 1) {
|
||||
slot = slot_;
|
||||
Delimiter(std::function<void(int)> func_ = nullptr, int delim_ = 1) {
|
||||
func = func_;
|
||||
delim = delim_;
|
||||
}
|
||||
TimerEvent slot;
|
||||
std::function<void(int)> func;
|
||||
int delim = 0;
|
||||
int tick = 0;
|
||||
};
|
||||
|
||||
void initFirst();
|
||||
void init() const;
|
||||
void destroy();
|
||||
|
||||
static void tickImpS(PITimer * t) { t->tickImp(); }
|
||||
void tickImp();
|
||||
void threadFunc();
|
||||
void adjustTimes();
|
||||
void execTick();
|
||||
|
||||
//! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing
|
||||
virtual void tick(void * data_, int delimiter) {}
|
||||
virtual void tick(int delimiter) {}
|
||||
|
||||
void * data_t = nullptr;
|
||||
std::atomic_bool lockRun, callEvents;
|
||||
PIThread * thread = nullptr;
|
||||
std::atomic_bool lockRun = {false}, callEvents = {true};
|
||||
PIMutex mutex_;
|
||||
TimerEvent ret_func = nullptr;
|
||||
TimerImplementation imp_mode = Thread;
|
||||
PISystemTime m_interval, m_interval_x5;
|
||||
PISystemTime m_time_next;
|
||||
std::function<void(int)> ret_func = nullptr;
|
||||
PIVector<Delimiter> delims;
|
||||
|
||||
mutable _PITimerBase * imp = nullptr;
|
||||
PIConditionVariable event;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user