Files
pip/libs/main/thread/pitimer.h
2022-12-14 13:56:19 +03:00

333 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! \file pitimer.h
* \ingroup Thread
* \~\brief
* \~english Timer
* \~russian Таймер
*/
/*
PIP - Platform Independent Primitives
Timer
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITIMER_H
#define PITIMER_H
#include "pithread.h"
#include "pitime.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;
PITimer * parent;
protected:
virtual bool startTimer(double interval_ms) = 0;
virtual bool stopTimer() = 0;
double interval_, deferred_delay;
bool deferred_, deferred_mode; // mode: true - date, false - delay
std::atomic_bool running_;
PIDateTime deferred_datetime;
};
class PIP_EXPORT PITimer: public PIObject {
PIOBJECT_SUBCLASS(PITimer, PIObject);
public:
NO_COPY_CLASS(PITimer);
//! \~english Constructs timer with PITimer::Thread implementation
//! \~russian Создает таймер с реализацией PITimer::Thread
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 "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);
virtual ~PITimer();
//! \~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);
//! \~english Returns if timer is started
//! \~russian Возвращает работает ли таймер
bool isRunning() const;
//! \~english Returns if timer is not started
//! \~russian Возвращает остановлен ли таймер
bool isStopped() const;
EVENT_HANDLER0(bool, start);
EVENT_HANDLER1(bool, start, double, interval_ms_d);
bool start(int interval_ms_i);
EVENT_HANDLER0(bool, restart);
//! \~english Start timer with \a interval() loop delay after "delay_msecs" delay
//! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs"
void startDeferred(double delay_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 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(); };
}
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
void setSlot(std::function<void(void *)> slot) {
ret_func = [slot](void * d, int) { slot(d); };
}
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
bool isCallQueuedEvents() const { return callEvents; }
//! \~english Set timer exec \a maybeCallQueuedEvents() at every tick
//! \~russian Установает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик
void setCallQueuedEvents(bool yes) { callEvents = yes; }
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, TimerEvent slot = 0) { delims << Delimiter(slot, delim); }
//! \~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);
}
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, std::function<void(void *)> slot) {
delims << Delimiter([slot](void * d, int) { slot(d); }, delim);
}
//! \~english Remove all frequency delimiters "delim"
//! \~russian Удаляет все делители частоты "delim"
void removeDelimiter(int delim) {
for (int i = 0; i < delims.size_s(); ++i)
if (delims[i].delim == delim) {
delims.remove(i);
i--;
}
}
EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); }
EVENT2(tickEvent, void *, data_, 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
//! \~english Stop and start timer with \a interval() loop delay
//! \~russian Остановить и запустить таймер с интервалом \a interval()
//! \fn bool stop(bool wait = true)
//! \brief
//! \~english Stop timer and wait for it finish if "wait"
//! \~russian Остановить таймер и если "wait" то дождаться остановки
//! \fn void clearDelimiters()
//! \brief
//! \~english Remove all frequency delimiters
//! \~russian Удаляет все делители частоты
//! \}
//! \events
//! \{
//! \fn void tickEvent(void * data, 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 для основного цикла
//! \}
protected:
struct PIP_EXPORT Delimiter {
Delimiter(TimerEvent slot_ = 0, int delim_ = 1) {
slot = slot_;
delim = delim_;
tick = 0;
}
TimerEvent slot;
int delim;
int tick;
};
void initFirst();
void init() const;
void destroy();
static void tickImpS(PITimer * t) { t->tickImp(); }
void tickImp();
//! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing
virtual void tick(void * data_, int delimiter) {}
void * data_t;
std::atomic_bool lockRun, callEvents;
PIMutex mutex_;
TimerEvent ret_func;
TimerImplementation imp_mode;
PIVector<Delimiter> delims;
mutable _PITimerBase * imp;
};
#endif // PITIMER_H