-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTimer.h
More file actions
127 lines (112 loc) · 4.04 KB
/
Timer.h
File metadata and controls
127 lines (112 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* Copyright (C) 2016-2020 Thomas Hauck - All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
The author would be happy if changes and
improvements were reported back to him.
Author: Thomas Hauck
Email: Thomas@fam-hauck.de
*/
#ifndef TIMER_H
#define TIMER_H
#include <condition_variable>
#include <atomic>
#include <thread>
#include <functional>
#include <chrono>
template<class T>
class Timer
{
public:
Timer(uint32_t tMilliSeconds, std::function<void(const Timer*, T*)> fTimeOut, T* pUserData = nullptr) : m_tMilliSeconds(tMilliSeconds), m_fTimeOut(fTimeOut), m_pUserData(pUserData)
{
atomic_init(&m_bStop, false);
atomic_init(&m_bIsStoped, false);
m_thWaitThread = std::thread([&]()
{
m_tStart = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
std::unique_lock<std::mutex> lock(m_mxCv);
do
{
std::chrono::milliseconds tNow = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
uint32_t nDifMilliSeconds = static_cast<uint32_t>((tNow - m_tStart).count());
if (tNow < m_tStart)
{
tNow = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
nDifMilliSeconds = static_cast<uint32_t>((tNow - m_tStart).count());
}
uint32_t tRestMilliSeconds = 1;
if (nDifMilliSeconds < m_tMilliSeconds)
tRestMilliSeconds = m_tMilliSeconds - nDifMilliSeconds;
if (m_cv.wait_for(lock, std::chrono::milliseconds(tRestMilliSeconds)) == std::cv_status::timeout)
{
if (m_fTimeOut != 0 && m_bStop == false)
m_fTimeOut(this, m_pUserData);
break;
}
} while (m_bStop == false);
m_bIsStoped = true;
});
}
virtual ~Timer()
{
Stop();
while (m_bIsStoped == false)
{
std::this_thread::sleep_for(std::chrono::microseconds(1));
const bool bIsLocked = m_mxCv.try_lock();
if (bIsLocked == true) // if it is not looked, the timeout is right now
{
m_cv.notify_all();
m_mxCv.unlock();
}
}
if (m_thWaitThread.joinable() == true)
m_thWaitThread.join();
}
void Reset() noexcept
{
m_tStart = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
const bool bIsLocked = m_mxCv.try_lock();
if (bIsLocked == true) // if it is not looked, the timeout is right now
{
m_cv.notify_all();
m_mxCv.unlock();
}
}
void Stop() noexcept
{
m_bStop = true;
const bool bIsLocked = m_mxCv.try_lock();
if (bIsLocked == true) // if it is not looked, the timeout is right now
{
m_cv.notify_all();
m_mxCv.unlock();
}
}
bool IsStopped() noexcept
{
return m_bIsStoped;
}
void SetNewTimeout(uint32_t nNewTime)
{
m_tMilliSeconds = nNewTime;
m_tStart = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
const bool bIsLocked = m_mxCv.try_lock();
if (bIsLocked == true) // if it is not looked, the timeout is right now
{
m_cv.notify_all();
m_mxCv.unlock();
}
}
private:
uint32_t m_tMilliSeconds;
std::chrono::milliseconds m_tStart;
std::function<void(const Timer*, T*)> m_fTimeOut;
T* m_pUserData;
std::atomic<bool> m_bStop;
std::atomic<bool> m_bIsStoped;
std::thread m_thWaitThread;
std::mutex m_mxCv;
std::condition_variable m_cv;
};
#endif // TIMER_H