Skip to content

Commit f74c13b

Browse files
committedFeb 20, 2023
New functionality added to the Timer class. Two new functions added - fsec_to_ms and ms_to_fsec.
1 parent 86808d2 commit f74c13b

File tree

4 files changed

+154
-24
lines changed

4 files changed

+154
-24
lines changed
 

‎DESCRIPTION.md

+42-1
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,45 @@ const char* const WeekdayNameShort[] = {
101101
Многофункциональный класс. Подходит для следующих задач:
102102

103103
* Измерение прошедшего времени, например задержки на выполнение участка кода.
104-
* Измерение среднего прошедшего времени, например задержки на выполнение участка кода.
104+
* Измерение среднего прошедшего времени
105105
* Асинхронный вызов callback-функции с заданным периодом
106106
* Асинхронный вызов callback-функции с изменяемым периодом
107+
* Асинхронный вызов callback-функции через заданное время в случае отсутствия обнуления счетчика
108+
109+
У таймера есть три режима:
110+
111+
```cpp
112+
enum class TimerMode {
113+
STRICT_INTERVAL, /**< First timer mode, where the timer calls the callback at fixed intervals by resetting its internal counter before the callback is called. */
114+
UNSTABLE_INTERVAL, /**< Second timer mode, where the timer resets its counter after the callback is called, making the period between callbacks unstable. */
115+
ONE_SHOT_AFTER_INTERVAL, /**< Third timer mode, where the timer calls the callback only once after a set amount of time, if its counter is not reset during that time. */
116+
};
117+
```
118+
119+
Пример использования режима STRICT_INTERVAL и UNSTABLE_INTERVAL:
120+
121+
```cpp
122+
ztime::Timer timer1(1000, ztime::Timer::TimerMode::STRICT_INTERVAL, [&](){
123+
std::cout << "event 1" << std::endl;
124+
});
125+
126+
ztime::Timer timer2(1000, ztime::Timer::TimerMode::UNSTABLE_INTERVAL, [&](){
127+
std::cout << "event 2" << std::endl;
128+
});
129+
```
130+
131+
Разница между режимами STRICT_INTERVAL и UNSTABLE_INTERVAL такая, что таймер с режимом UNSTABLE_INTERVAL перед обнулением счетчика ожидает завершение задачи в callback-функции, а режим STRICT_INTERVAL обнуляет счетчик перед вызовом callback-функции.
132+
133+
Пример использования режима ONE_SHOT_AFTER_INTERVAL:
134+
135+
```cpp
136+
ztime::Timer timer(1000, ztime::Timer::TimerMode::ONE_SHOT_AFTER_INTERVAL, [&](){
137+
std::cout << "event" << std::endl;
138+
});
139+
140+
// Откладываем вызов callback
141+
timer.reset_event();
142+
```
107143
108144
### MoonPhase
109145
@@ -359,6 +395,11 @@ cout << "to_string " << ztime::to_string("%hh:%mm.%sss",ztime::get_ftimestamp(31
359395

360396
### Различные преобразования и вычисления
361397

398+
* sec_to_ms - Преобразовать секунды в миллисекунды
399+
* fsec_to_ms - Преобразовать секунды с плавающей точкой в миллисекунды
400+
* ms_to_sec - Преобразовать миллисекунды в секунды
401+
* ms_to_fsec - Преобразовать миллисекунды в секунды с плавающей точкой
402+
362403
* timestamp_t get_first_timestamp_year(const timestamp_t timestamp = get_timestamp()) - Получить метку времени в начале года
363404
* timestamp_t get_last_timestamp_year(const timestamp_t timestamp = get_timestamp()) - Получить метку времени в конце года
364405
* timestamp_t get_first_timestamp_month(const timestamp_t timestamp = get_timestamp()) - Получить метку времени в начале текущего месяца

‎code_blocks/test/timer_event.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ int main() {
77
std::cout << "test async-timer" << std::endl;
88
{
99
ztime::Timer timer_a;
10-
ztime::Timer timer(1000, [&](){
10+
ztime::Timer timer(1000, ztime::Timer::TimerMode::STRICT_INTERVAL, [&](){
1111
std::cout << "elapsed: " << timer_a.elapsed() << std::endl;
1212
timer_a.reset();
1313
});

‎src/parts/ztime_timer.hpp

+87-20
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,31 @@ namespace ztime {
4141

4242
std::atomic<uint32_t> period_ms = ATOMIC_VAR_INIT(0);
4343

44+
enum class TimerMode {
45+
STRICT_INTERVAL, /**< First timer mode, where the timer calls the callback at fixed intervals by resetting its internal counter before the callback is called. */
46+
UNSTABLE_INTERVAL, /**< Second timer mode, where the timer resets its counter after the callback is called, making the period between callbacks unstable. */
47+
ONE_SHOT_AFTER_INTERVAL, /**< Third timer mode, where the timer calls the callback only once after a set amount of time, if its counter is not reset during that time. */
48+
};
49+
4450
Timer() : m_start_time(clock_t::now()) {};
4551

52+
53+
Timer( const uint32_t interval_ms,
54+
const TimerMode mode,
55+
const std::function<void()> &callback) : Timer() {
56+
create_event(interval_ms, mode, callback);
57+
}
58+
4659
/** \brief Non-blocking async timer constructor
4760
* \param callback Your callback function that will be called asynchronously with a period of period_ms
4861
*/
49-
Timer(const uint32_t interval_ms, const std::function<void()> &callback) : Timer() {
50-
create_event(interval_ms, callback);
51-
}
52-
53-
Timer(const std::function<void()> &callback) : Timer(0, callback) {
54-
62+
Timer(const std::function<void()> &callback) :
63+
Timer(0, TimerMode::UNSTABLE_INTERVAL, callback) {
5564
}
5665

5766
~Timer() {
5867
m_shutdown = true;
68+
m_cv.notify_one();
5969
if(m_timer_future.valid()) {
6070
try {
6171
m_timer_future.wait();
@@ -64,33 +74,54 @@ namespace ztime {
6474
}
6575
}
6676

67-
bool create_event(const uint32_t interval_ms, const std::function<void()> &callback) {
77+
bool create_event(
78+
const uint32_t interval_ms,
79+
const TimerMode mode,
80+
const std::function<void()> &callback) {
6881
try {
69-
std::call_once(m_once, [&, callback](){
82+
std::call_once(m_once, [&, callback, mode]() {
7083
if (callback) {
7184
period_ms = interval_ms;
72-
m_timer_future = std::async(std::launch::async, [&, callback]() {
73-
74-
std::mutex mtx;
75-
std::condition_variable cv;
85+
m_timer_future = std::async(std::launch::async, [&, callback, mode]() {
7686

7787
using ms_t = std::chrono::duration<uint32_t, std::ratio<1, 1000>>;
88+
using ms64_t = std::chrono::duration<uint64_t, std::ratio<1, 1000>>;
89+
7890
std::chrono::time_point<clock_t> start_time = clock_t::now();
7991

92+
if (mode == TimerMode::ONE_SHOT_AFTER_INTERVAL) {
93+
m_event_start_time = clock_t::now();
94+
}
95+
8096
while (!false) {
81-
std::unique_lock<std::mutex> lock(mtx);
82-
cv.wait_for(lock, std::chrono::milliseconds(1));
97+
std::unique_lock<std::mutex> lock(m_event_mtx);
98+
m_cv.wait_for(lock, std::chrono::milliseconds(1));
99+
lock.unlock();
83100

84101
if (m_shutdown) return;
85102
if (!period_ms) continue;
86103

87-
const uint32_t elapsed =
88-
std::chrono::duration_cast<ms_t>(
89-
clock_t::now() - start_time).count();
104+
if (mode == TimerMode::ONE_SHOT_AFTER_INTERVAL) {
105+
std::unique_lock<std::mutex> lock(m_event_time);
106+
const uint64_t elapsed = get_elapsed<uint64_t, ms64_t>(m_event_start_time);
107+
if (elapsed < period_ms) continue;
108+
if (m_once_event) continue;
109+
m_once_event = true;
110+
lock.unlock();
111+
callback();
112+
continue;
113+
}
114+
115+
const uint32_t elapsed = get_elapsed<uint32_t, ms_t>(start_time);
90116

91117
if (elapsed >= period_ms) {
92-
start_time = clock_t::now();
118+
if (mode == TimerMode::STRICT_INTERVAL) {
119+
start_time = clock_t::now();
120+
}
93121
callback();
122+
if (mode == TimerMode::UNSTABLE_INTERVAL) {
123+
start_time = clock_t::now();
124+
}
94125
}
95126
}
96127
});
@@ -103,7 +134,27 @@ namespace ztime {
103134
}
104135

105136
bool create_event(const std::function<void()> &callback) {
106-
return create_event(0, callback);
137+
return create_event(0, TimerMode::UNSTABLE_INTERVAL, callback);
138+
}
139+
140+
/** \brief Reset the event timer counter
141+
* This method resets the event timer counter in ONE_SHOT_AFTER_INTERVAL mode
142+
* The method should be called within the specified interval to prevent the timer from calling the callback
143+
*/
144+
inline void reset_event() noexcept {
145+
std::unique_lock<std::mutex> lock(m_event_time);
146+
m_once_event = false;
147+
m_event_start_time = clock_t::now();
148+
}
149+
150+
inline void set_name(const std::string &name) noexcept {
151+
std::unique_lock<std::mutex> lock(m_name_mtx);
152+
m_name = name;
153+
}
154+
155+
inline std::string get_name() noexcept {
156+
std::unique_lock<std::mutex> lock(m_name_mtx);
157+
return m_name;
107158
}
108159

109160
/** \brief Reset the timer value
@@ -234,7 +285,23 @@ namespace ztime {
234285
return m_start_time;
235286
}
236287

237-
std::future<void> m_timer_future;
288+
template<class T1, class T2>
289+
inline T1 get_elapsed(std::chrono::time_point<clock_t> &start_time) noexcept {
290+
return std::chrono::duration_cast<T2>(
291+
clock_t::now() - start_time).count();
292+
}
293+
294+
std::string m_name;
295+
std::mutex m_name_mtx;
296+
297+
std::mutex m_event_time;
298+
std::chrono::time_point<clock_t> m_event_start_time;
299+
bool m_once_event = false;
300+
301+
std::future<void> m_timer_future;
302+
std::mutex m_event_mtx;
303+
std::condition_variable m_cv;
304+
238305
std::atomic<bool> m_shutdown = ATOMIC_VAR_INIT(false);
239306
std::once_flag m_once;
240307
};

‎src/ztime.hpp

+24-2
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,38 @@
4242

4343
namespace ztime {
4444

45-
// Функция для преобразования метки времени из секунд в миллисекунды
45+
/** \brief Function for converting a timestamp from seconds to milliseconds
46+
* \param t Timestamp in seconds
47+
* \return Timestamp in milliseconds
48+
*/
4649
constexpr inline timestamp_ms_t sec_to_ms(const timestamp_t t) noexcept {
4750
return t * MS_PER_SEC;
4851
}
4952

50-
// Функция для преобразования метки времени из миллисекунд в секунды
53+
/** \brief Function for converting a timestamp from seconds to milliseconds
54+
* \param t Timestamp in floating-point seconds
55+
* \return Timestamp in milliseconds
56+
*/
57+
constexpr inline timestamp_ms_t fsec_to_ms(const ftimestamp_t t) noexcept {
58+
return (timestamp_ms_t)(t * (ftimestamp_t)MS_PER_SEC + 0.5);
59+
}
60+
61+
/** \brief Function for converting a timestamp from milliseconds to seconds
62+
* \param t Timestamp in milliseconds
63+
* \return Timestamp in seconds
64+
*/
5165
constexpr inline timestamp_t ms_to_sec(const timestamp_ms_t t_ms) noexcept {
5266
return t_ms / MS_PER_SEC;
5367
}
5468

69+
/** \brief Function for converting a timestamp from milliseconds to seconds
70+
* \param t Timestamp in milliseconds
71+
* \return Timestamp in floating-point seconds
72+
*/
73+
constexpr inline ftimestamp_t ms_to_fsec(const timestamp_ms_t t_ms) noexcept {
74+
return t_ms / (ftimestamp_t)MS_PER_SEC;
75+
}
76+
5577
/** \brief Получить миллисекунду секунды
5678
* \return Миллисекунда секунды
5779
*/

0 commit comments

Comments
 (0)
Please sign in to comment.