MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
atomic_timed_wait.hpp
浏览该文件的文档.
1#ifndef MSTL_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
2#define MSTL_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
3
10
14
17
18using wait_clock_t = steady_clock;
19
29template <typename Clock, typename Dur>
30wait_clock_t::time_point to_wait_clock(const time_point<Clock, Dur>& time_point) noexcept {
31 const typename Clock::time_point clock_entry = Clock::now();
32 const wait_clock_t::time_point wait_entry = wait_clock_t::now();
33 const auto delta = time_point - clock_entry;
34 return wait_entry + _MSTL ceil<wait_clock_t::duration>(delta);
35}
36
45template <typename Dur>
46wait_clock_t::time_point to_wait_clock(const time_point<wait_clock_t, Dur>& time_point) noexcept {
48}
49
60template <typename Dur>
61bool __platform_wait_until_impl(
62 const platform_wait_t* addr, const platform_wait_t old,
63 const time_point<wait_clock_t, Dur>& timeout) noexcept {
64 const bool has_timeout = (timeout != wait_clock_t::time_point::max());
65
66 if (!has_timeout) {
67 _MSTL futex_wait(const_cast<void*>(static_cast<const void*>(addr)), old);
68 return true;
69 }
70
71 const auto now = wait_clock_t::now();
72 if (timeout <= now) {
73 return false;
74 }
75
76#ifdef MSTL_PLATFORM_WINDOWS__
77 const auto dur = timeout - now;
78 const auto sec = _MSTL time_cast<seconds>(dur);
79 const auto ns = _MSTL time_cast<nanoseconds>(dur - sec);
80#else
81 const auto sys_timeout = steady_clock::to_system<Dur>(timeout);
82 const auto sys_now = system_clock::now();
83 if (sys_timeout <= sys_now) {
84 return false;
85 }
86 const auto sys_dur = sys_timeout - sys_now;
87 const auto sec = _MSTL time_cast<seconds>(sys_dur);
88 const auto ns = _MSTL time_cast<nanoseconds>(sys_dur - sec);
89#endif
90
92 const_cast<void*>(static_cast<const void*>(addr)),
93 old, true, sec.count(), ns.count(), true);
94}
95
96template <typename Clock, typename Dur>
98__platform_wait_until_dispatch(const platform_wait_t* addr, platform_wait_t old,
100 return _INNER __platform_wait_until_impl(addr, old, timeout);
101}
102
103template <typename Clock, typename Dur>
105__platform_wait_until_dispatch(const platform_wait_t* addr, platform_wait_t old,
107 if (!_INNER __platform_wait_until_impl(addr, old, _INNER to_wait_clock(timeout))) {
108 if (Clock::now() < timeout) return true;
109 }
110 return false;
111}
112
115
121
133template <typename Clock, typename Dur>
135 const platform_wait_t* addr, platform_wait_t old,
137 return _INNER __platform_wait_until_dispatch(addr, old, timeout);
138}
139 // Futex
141
147
157struct timed_backoff_spin_policy {
158 _INNER wait_clock_t::time_point deadline;
159 _INNER wait_clock_t::time_point start_time;
160
161 template <typename Clock, typename Dur>
162 timed_backoff_spin_policy(
163 time_point<Clock, Dur> deadline_time = Clock::time_point::max(),
164 time_point<Clock, Dur> start_time_point = Clock::now()) noexcept
165 : deadline(_INNER to_wait_clock(deadline_time)),
166 start_time(_INNER to_wait_clock(start_time_point)) {}
167
168 bool operator ()() const noexcept {
169 const auto now = _INNER wait_clock_t::now();
170 if (deadline <= now) {
171 return false;
172 }
173
174 const auto elapsed = now - start_time;
175 if (elapsed > 128_ms) {
176 this_thread::sleep_for(64_ms);
177 } else if (elapsed > 64_us) {
178 this_thread::sleep_for(elapsed / 2);
179 } else if (elapsed > 4_us) {
180 this_thread::yield();
181 } else {
182 return false;
183 }
184 return true;
185 }
186};
187
190
197struct timed_waiter_pool : waiter_pool_base {
207 template <typename Clock, typename Dur>
208 bool do_wait_until(platform_wait_t* addr, platform_wait_t old,
210 return _MSTL futex_wait_until(addr, old, timeout);
211 }
212};
213
221template <typename EntersWait>
222struct timed_waiter : waiter_base<timed_waiter_pool> {
223 using base_type = waiter_base<timed_waiter_pool>;
224
225private:
226 template <bool Wait = EntersWait::value, enable_if_t<Wait, int> = 0>
227 MSTL_ALWAYS_INLINE void enter() const noexcept {
228 waiter_.waiter_enter_wait();
229 }
230 template <bool Wait = EntersWait::value, enable_if_t<!Wait, int> = 0>
231 MSTL_ALWAYS_INLINE void enter() const noexcept {}
232
233 template <bool Wait = EntersWait::value, enable_if_t<Wait, int> = 0>
234 MSTL_ALWAYS_INLINE void leave() const noexcept {
235 waiter_.waiter_leave_wait();
236 }
237 template <bool Wait = EntersWait::value, enable_if_t<!Wait, int> = 0>
238 MSTL_ALWAYS_INLINE void leave() const noexcept {}
239
240public:
246 template <typename T>
247 explicit timed_waiter(const T* addr) noexcept
248 : base_type(addr) {
249 enter();
250 }
251
255 ~timed_waiter() {
256 leave();
257 }
258
270 template <typename T, typename Func, typename Clock, typename Dur>
271 bool waiter_do_wait_until_v(T old, Func func,
272 const time_point<Clock, Dur>& timeout) noexcept {
273 platform_wait_t value;
274 if (base_type::waiter_do_spin(old, _MSTL move(func), value,
275 timed_backoff_spin_policy(timeout))) {
276 return true;
277 }
278 return base_type::waiter_.do_wait_until(base_type::addr_, value, timeout);
279 }
280
291 template <typename Pred, typename Clock, typename Dur>
292 bool waiter_do_wait_until(Pred pred, platform_wait_t value,
293 const time_point<Clock, Dur>& timeout) noexcept {
294 for (auto now = Clock::now(); now < timeout; now = Clock::now()) {
295 if (base_type::waiter_.do_wait_until(base_type::addr_, value, timeout) && pred()) {
296 return true;
297 }
298 if (base_type::waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout, now)))
299 return true;
300 }
301 return false;
302 }
303
313 template <typename Pred, typename Clock, typename Dur>
314 bool waiter_do_wait_until(Pred pred, const time_point<Clock, Dur>& timeout) noexcept {
315 platform_wait_t value;
316 if (this->waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout))) {
317 return true;
318 }
319 return this->waiter_do_wait_until(pred, value, timeout);
320 }
321
333 template <typename T, typename Func, typename Rep, typename Period>
334 bool waiter_do_wait_for_v(T old, Func func, const duration<Rep, Period>& rt) noexcept {
335 platform_wait_t value;
336 if (base_type::waiter_do_spin_v(old, _MSTL move(func), value)) {
337 return true;
338 }
339 if (!rt.count()) {
340 return false;
341 }
342 auto rtc = ceil<wait_clock_t::duration>(rt);
343 return base_type::waiter_.do_wait_until(base_type::addr_, value, steady_clock::now() + rtc);
344 }
345
355 template <typename Pred, typename Rep, typename Period>
356 bool waiter_do_wait_for(Pred pred, const duration<Rep, Period>& rt) noexcept {
357 platform_wait_t value;
358 if (base_type::waiter_do_spin(pred, value)) {
359 return true;
360 }
361 if (!rt.count()) {
362 return false;
363 }
364 auto rtc = ceil<wait_clock_t::duration>(rt);
365 return this->waiter_do_wait_until(pred, value, steady_clock::now() + rtc);
366 }
367};
368
370using enters_timed_wait = timed_waiter<true_type>;
371
373using bare_timed_wait = timed_waiter<false_type>;
374
377
392template <typename T, typename Func, typename Clock, typename Dur>
393bool atomic_wait_address_until_v(const T* addr, T&& old,
394 Func&& func, const time_point<Clock, Dur>& timeout) noexcept {
395 _INNER enters_timed_wait waiter{addr};
396 return waiter.waiter_do_wait_until_v(old, func, timeout);
397}
398
412template <typename T, typename Pred, typename Clock, typename Dur>
413bool atomic_wait_address_until(const T* addr, Pred pred,
414 const time_point<Clock, Dur>& timeout) noexcept {
415 _INNER enters_timed_wait waiter{addr};
416 return waiter.waiter_do_wait_until(pred, timeout);
417}
418
431template <typename Pred, typename Clock, typename Dur>
432bool atomic_wait_address_until(const platform_wait_t* addr, Pred pred,
433 const time_point<Clock, Dur>& timeout) noexcept {
434 _INNER bare_timed_wait waiter{addr};
435 return waiter.waiter_do_wait_until(pred, timeout);
436}
437
452template <typename T, typename Func, typename Rep, typename Period>
453bool atomic_wait_address_for_v(const T* addr, T&& old, Func&& func,
454 const duration<Rep, Period>& rt) noexcept {
455 _INNER enters_timed_wait waiter{addr};
456 return waiter.waiter_do_wait_for_v(old, func, rt);
457}
458
472template <typename T, typename Pred, typename Rep, typename Period>
473bool atomic_wait_address_for(const T* addr, Pred pred,
474 const duration<Rep, Period>& rt) noexcept {
475 _INNER enters_timed_wait waiter{addr};
476 return waiter.waiter_do_wait_for(pred, rt);
477}
478
491template <typename Pred, typename Rep, typename Period>
492bool atomic_wait_address_for(const platform_wait_t* addr, Pred pred,
493 const duration<Rep, Period>& rt) noexcept {
494 _INNER bare_timed_wait waiter{addr};
495 return waiter.waiter_do_wait_for(pred, rt);
496}
497 // AtomicOperations
499
501#endif // MSTL_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
MSTL原子等待/通知机制
MSTL时钟类型
bool atomic_wait_address_until_v(const T *addr, T &&old, Func &&func, const time_point< Clock, Dur > &timeout) noexcept
基于值的原子定时等待(绝对时间)
bool atomic_wait_address_until(const T *addr, Pred pred, const time_point< Clock, Dur > &timeout) noexcept
基于谓词的原子定时等待(绝对时间)
bool atomic_wait_address_for_v(const T *addr, T &&old, Func &&func, const duration< Rep, Period > &rt) noexcept
基于值的原子定时等待(相对时间)
bool atomic_wait_address_for(const T *addr, Pred pred, const duration< Rep, Period > &rt) noexcept
基于谓词的原子定时等待(相对时间)
constexpr ToDur time_cast(const duration< Rep, Period > &value)
持续时间类型转换
int platform_wait_t
平台等待类型别名
bool futex_wait_until(const platform_wait_t *addr, platform_wait_t old, const time_point< Clock, Dur > &timeout)
FUTEX定时等待函数
void MSTL_API futex_wait(void *addr, platform_wait_t value) noexcept
无限期等待FUTEX
MSTL_CONST_FUNCTION MSTL_CONSTEXPR14 decimal_t ceil(const decimal_t x) noexcept
向上取整
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_INNER__
结束inner命名空间
#define _INNER
inner命名空间前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
#define MSTL_BEGIN_INNER__
开始inner命名空间
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
持续时间类模板
稳定时钟
static time_point now() noexcept
获取当前时间点
static system_clock::time_point to_system(const _MSTL time_point< steady_clock, Dur > &tp)
将稳定时钟转为系统时钟
static time_point now() noexcept
获取当前时间点
时间点类模板