MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
timer.hpp
1#ifndef MSTL_CORE_ASYNC_TIMER_HPP__
2#define MSTL_CORE_ASYNC_TIMER_HPP__
3#include "../container/map.hpp"
4#include "../container/set.hpp"
6#include "thread.hpp"
8#include "atomic.hpp"
10
11template <typename Clock>
12class timer_scheduler {
13public:
14 using clock_type = Clock;
15 using time_point = typename clock_type::time_point;
16 using duration = typename clock_type::duration;
17 using token = size_t;
18 using handler_type = _MSTL function<void()>;
19
20private:
21 struct node {
22 time_point expire;
23 token id;
24 handler_type handler;
25
26 node(time_point exp, const token tid, handler_type&& h)
27 : expire(exp), id(tid), handler(_MSTL move(h)) {}
28
29 bool operator <(const node& other) const {
30 if (expire < other.expire) return true;
31 if (expire > other.expire) return false;
32 return id < other.id;
33 }
34 };
35
36 _MSTL set<node> nodes_;
37 _MSTL map<token, typename _MSTL set<node>::iterator> node_map_;
38
39 _MSTL thread thread_;
40 _MSTL mutex mutex_;
41 _MSTL condition_variable cv_;
42 token next_id_;
43 _MSTL atomic_bool stopped_;
44
45 friend class thread_pool;
46
47private:
48 void run() {
49 while (!stopped_.load()) {
50 _MSTL smart_lock<_MSTL mutex> lock(mutex_);
51
52 if (nodes_.empty()) {
53 cv_.wait(lock, [this] {
54 return stopped_.load() || !nodes_.empty();
55 });
56 if (stopped_.load()) break;
57 }
58
59 time_point now = clock_type::now();
60 while (!nodes_.empty() && nodes_.begin()->expire <= now) {
61 auto it = nodes_.begin();
62 node current_node = *it;
63 nodes_.erase(it);
64 node_map_.erase(current_node.id);
65
66 lock.unlock_quiet();
67 if (!stopped_.load()) {
68 current_node.handler();
69 }
70 lock.lock_quiet();
71 now = clock_type::now();
72 }
73
74 if (!nodes_.empty()) {
75 time_point next_expire = nodes_.begin()->expire;
76 cv_.wait_until(lock, next_expire);
77 }
78 }
79 }
80
81public:
82 timer_scheduler() : next_id_(0), stopped_(false) {
83 thread_ = _MSTL thread(&timer_scheduler::run, this);
84 }
85
86 ~timer_scheduler() {
87 stopped_.store(true);
88 cv_.notify_one();
89 if (thread_.joinable()) {
90 thread_.join();
91 }
92 }
93
94 timer_scheduler(const timer_scheduler&) = delete;
95 timer_scheduler& operator =(const timer_scheduler&) = delete;
96 timer_scheduler(timer_scheduler&&) = default;
97 timer_scheduler& operator =(timer_scheduler&&) = default;
98
99 token add_task(time_point expire, handler_type&& handler) {
100 _MSTL smart_lock<_MSTL mutex> lock(mutex_);
101 token id = next_id_++;
102
103 const bool is_earliest = nodes_.empty() || expire < nodes_.begin()->expire;
104
105 node new_node(expire, id, _MSTL move(handler));
106 auto result = nodes_.insert(new_node);
107 node_map_[id] = result.first;
108
109 lock.unlock_quiet();
110
111 if (is_earliest) {
112 cv_.notify_one();
113 }
114
115 return id;
116 }
117
118 bool cancel(token id) {
119 _MSTL smart_lock<_MSTL mutex> lock(mutex_);
120 auto it_map = node_map_.find(id);
121 if (it_map == node_map_.end()) {
122 return false;
123 }
124
125 const bool is_earliest = (it_map->second == nodes_.begin());
126 nodes_.erase(it_map->second);
127 node_map_.erase(it_map);
128
129 lock.unlock_quiet();
130
131 if (is_earliest) {
132 cv_.notify_one();
133 }
134
135 return true;
136 }
137
138 void cancel_all() {
139 _MSTL smart_lock<_MSTL mutex> lock(mutex_);
140 nodes_.clear();
141 node_map_.clear();
142 lock.unlock_quiet();
143 cv_.notify_one();
144 }
145
146 MSTL_NODISCARD size_t size() const {
147 _MSTL lock<_MSTL mutex> lock(const_cast<_MSTL mutex&>(mutex_));
148 return nodes_.size();
149 }
150};
151
152
153template <typename Clock>
154class basic_timer {
155public:
156 using clock_type = Clock;
157 using time_point = typename clock_type::time_point;
158 using duration = typename clock_type::duration;
159 using token = typename timer_scheduler<Clock>::token;
160 using handler_type = typename timer_scheduler<Clock>::handler_type;
161
162private:
163 timer_scheduler<Clock> scheduler_{};
164 token task_id_ = 0;
165 time_point expire_ = clock_type::now();
166
167public:
168 basic_timer() = default;
169 ~basic_timer() { cancel(); }
170
171 basic_timer(const basic_timer&) = delete;
172 basic_timer& operator =(const basic_timer&) = delete;
173
174 basic_timer(basic_timer&& other) noexcept
175 : scheduler_(other.scheduler_)
176 , task_id_(other.task_id_)
177 , expire_(other.expire_) {
178 other.task_id_ = 0;
179 }
180
181 basic_timer& operator =(basic_timer&& other) noexcept {
182 if (this != &other) {
183 cancel();
184 task_id_ = other.task_id_;
185 expire_ = other.expire_;
186 other.task_id_ = 0;
187 }
188 return *this;
189 }
190
191 void expires_at(const time_point& expiry_time) {
192 cancel();
193 expire_ = expiry_time;
194 }
195
196 void expires_after(const duration& expiry_duration) {
197 cancel();
198 expire_ = clock_type::now() + expiry_duration;
199 }
200
201 void expires_from_now(const int64_t milliseconds) {
202 expires_after(_MSTL milliseconds(milliseconds));
203 }
204
205 MSTL_NODISCARD time_point expiry() const { return expire_; }
206 MSTL_NODISCARD bool is_active() const { return task_id_ != 0; }
207
208 template <typename WaitHandler>
209 void async_wait(WaitHandler&& handler) {
210 cancel();
211 task_id_ = scheduler_.add_task(expire_,
212 handler_type(_MSTL forward<WaitHandler>(handler)));
213 }
214
215 void cancel() {
216 if (task_id_ != 0) {
217 scheduler_.cancel(task_id_);
218 task_id_ = 0;
219 }
220 }
221};
222
223using steady_timer = basic_timer<steady_clock>;
224using system_timer = basic_timer<system_clock>;
225
227#endif // MSTL_CORE_ASYNC_TIMER_HPP__
MSTL原子类型完整实现
MSTL条件变量行为
MSTL通用函数包装器
MSTL_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
atomic< bool > atomic_bool
布尔原子类型
long long int64_t
64位有符号整数类型
duration< int64_t, milli > milliseconds
毫秒持续时间
lock< Mutex, true > smart_lock
智能锁管理器的便捷类型别名
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
MSTL_NODISCARD constexpr bool operator<(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept
小于比较运算符
uint64_t size_t
无符号大小类型
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
MSTL_ALWAYS_INLINE_INLINE thread::id id() noexcept
获取当前线程标识符
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
MSTL线程支持