/*! \file pitimer.h * \ingroup Thread * \~\brief * \~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 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 . */ #ifndef PITIMER_H #define PITIMER_H #include "piconditionvar.h" #include "piobject.h" #include "pisystemtime.h" 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 a timer without a tick callback. //! \~russian Создает таймер без обратного вызова тика. explicit PITimer(); //! \~english Constructs a timer with a callback that receives the delimiter value. //! \~russian Создает таймер с обратным вызовом, принимающим значение делителя. explicit PITimer(std::function func); //! \~english Constructs a timer with a callback that ignores the delimiter value. //! \~russian Создает таймер с обратным вызовом, игнорирующим значение делителя. explicit PITimer(std::function func); //! \~english Destroys the timer and stops its internal worker thread. //! \~russian Уничтожает таймер и останавливает его внутренний рабочий поток. virtual ~PITimer(); //! \~english Returns the configured base interval between main ticks. //! \~russian Возвращает настроенный базовый интервал между основными тиками. PISystemTime interval() const; //! \~english Sets the base interval. If the timer is running, restarts it with the new value. //! \~russian Устанавливает базовый интервал. Если таймер запущен, перезапускает его с новым значением. void setInterval(PISystemTime interval); //! \~english Returns whether the timer thread is currently running. //! \~russian Возвращает, работает ли сейчас поток таймера. bool isRunning() const; //! \~english Returns whether stop has been requested and shutdown is still in progress. //! \~russian Возвращает, был ли запрошен останов и идет ли еще завершение. bool isStopping() const; //! \~english Waits until the timer finishes. Returns \b false if the timeout expires first. //! \~russian Ожидает завершения таймера. Возвращает \b false, если таймаут истек раньше. bool waitForFinish(PISystemTime timeout = {}); //! \~english Sets the base interval and starts the timer. //! \~russian Устанавливает базовый интервал и запускает таймер. bool start(PISystemTime interval); //! \~english Sets the base interval and tick callback, then starts the timer. //! \~russian Устанавливает базовый интервал и обратный вызов тика, затем запускает таймер. bool start(PISystemTime interval, std::function 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)); } //! \~english Deprecated overload of \a stopAndWait() that accepts milliseconds. //! \~russian Устаревшая перегрузка \a stopAndWait(), принимающая миллисекунды. void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); } //! \~english Requests stop and waits for the worker thread to finish. //! \~russian Запрашивает остановку и ожидает завершения рабочего потока. void stopAndWait(PISystemTime timeout = {}); //! \~english Sets a tick callback that ignores the delimiter value. //! \~russian Устанавливает обратный вызов тика, игнорирующий значение делителя. void setSlot(std::function func); //! \~english Sets a tick callback that receives the current delimiter value. //! \~russian Устанавливает обратный вызов тика, принимающий текущее значение делителя. void setSlot(std::function func); //! \~english Enables locking of the internal mutex around tick processing. //! \~russian Включает блокировку внутреннего мьютекса вокруг обработки тиков. void needLockRun(bool need) { lockRun = need; } //! \~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 Enables or disables queued-delivery draining through \a maybeCallQueuedEvents() on each main tick. //! \~russian Включает или отключает обработку отложенной доставки через \a maybeCallQueuedEvents() на каждом основном тике. void setCallQueuedEvents(bool yes) { callEvents = yes; } //! \~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 func = nullptr); //! \~english Adds a delimiter with a callback that ignores the delimiter value. //! \~russian Добавляет делитель с обратным вызовом, игнорирующим значение делителя. void addDelimiter(int delim, std::function func); //! \~english Adds a delimiter with a pointer-based callback signature. //! \~russian Добавляет делитель с сигнатурой обратного вызова, принимающей указатель. void addDelimiter(int delim, std::function slot); //! \~english Removes all delimiters with value \a delim. //! \~russian Удаляет все делители со значением \a delim. void removeDelimiter(int delim); //! \handlers //! \{ //! \fn bool start() //! \brief //! \~english Starts the timer with the current \a interval(). //! \~russian Запускает таймер с текущим значением \a interval(). EVENT_HANDLER0(bool, start); //! \fn bool restart() //! \brief //! \~english Stops the timer, then starts it again with the current \a interval(). //! \~russian Останавливает таймер, затем снова запускает его с текущим значением \a interval(). EVENT_HANDLER0(bool, restart); //! \fn bool stop() //! \brief //! \~english Requests stop and wakes the timer thread, but does not wait for completion. //! \~russian Запрашивает остановку и пробуждает поток таймера, но не ожидает завершения. EVENT_HANDLER0(void, stop); //! \fn void clearDelimiters() //! \brief //! \~english Remove all frequency delimiters //! \~russian Удаляет все делители частоты EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); } //! \fn void lock() //! \brief //! \~english Locks the internal timer mutex. //! \~russian Блокирует внутренний мьютекс таймера. EVENT_HANDLER0(void, lock) { mutex_.lock(); } //! \fn void unlock() //! \brief //! \~english Unlocks the internal timer mutex. //! \~russian Разблокирует внутренний мьютекс таймера. EVENT_HANDLER0(void, unlock) { mutex_.unlock(); } //! \} //! \events //! \{ //! \fn void tickEvent(int delimiter) //! \brief //! \~english Raised on each timer tick and on configured delimiter ticks. //! \~russian Вызывается на каждом тике таймера и на настроенных тиках делителей. //! \~\details //! \~english //! "delimiter" is the frequency delimiter, 1 for the main loop. //! \~russian //! "delimiter" - делитель частоты, 1 для основного цикла. EVENT1(tickEvent, int, delimiter); //! \} protected: struct PIP_EXPORT Delimiter { Delimiter(std::function func_ = nullptr, int delim_ = 1) { func = std::move(func_); delim = delim_; } std::function func; int delim = 0; int tick = 0; }; void initFirst(); void init() const; void threadFunc(); void adjustTimes(); void execTick(); //! \~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; std::atomic_bool lockRun = {false}, callEvents = {true}; PIMutex mutex_; PISystemTime m_interval, m_interval_x5; PISystemTime m_time_next; std::function ret_func = nullptr; std::function ret_func_delim = nullptr; PIVector delims; PIConditionVariable event; }; #endif // PITIMER_H