NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
atomic_timed_wait.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
2#define NEFORCE_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
3
10
13NEFORCE_BEGIN_NAMESPACE__
14
20
22NEFORCE_BEGIN_INNER__
23
24using wait_clock_t = steady_clock;
25
35template <typename Clock, typename Dur>
36wait_clock_t::time_point to_wait_clock(const time_point<Clock, Dur>& time_point) noexcept {
37 const typename Clock::time_point clock_entry = Clock::now();
38 const wait_clock_t::time_point wait_entry = wait_clock_t::now();
39 const auto delta = time_point - clock_entry;
40 return wait_entry + ceil<wait_clock_t::duration>(delta);
41}
42
51template <typename Dur>
52wait_clock_t::time_point to_wait_clock(const time_point<wait_clock_t, Dur>& time_point) noexcept {
54}
55
66template <typename Dur>
67bool __platform_wait_until_impl(const platform_wait_t* addr, const platform_wait_t old,
68 const time_point<wait_clock_t, Dur>& timeout) noexcept {
69 const bool has_timeout = (timeout != wait_clock_t::time_point::max());
70
71 if (!has_timeout) {
72 futex_wait(const_cast<void*>(static_cast<const void*>(addr)), old);
73 return true;
74 }
75
76 const auto now = wait_clock_t::now();
77 if (timeout <= now) {
78 return false;
79 }
80
81#ifdef NEFORCE_PLATFORM_WINDOWS
82 const auto dur = timeout - now;
83 const auto sec = time_cast<seconds>(dur);
84 const auto ns = time_cast<nanoseconds>(dur - sec);
85#else
86 const auto sys_timeout = steady_clock::to_system<Dur>(timeout);
87 const auto sys_now = system_clock::now();
88 if (sys_timeout <= sys_now) {
89 return false;
90 }
91 const auto sys_dur = sys_timeout - sys_now;
92 const auto sec = time_cast<seconds>(sys_dur);
93 const auto ns = time_cast<nanoseconds>(sys_dur - sec);
94#endif
95
96 return _NEFORCE futex_wait_until(const_cast<void*>(static_cast<const void*>(addr)), old, true, sec.count(),
97 ns.count(), true);
98}
99
100template <typename Clock, typename Dur>
102__platform_wait_until_dispatch(const platform_wait_t* addr, platform_wait_t old,
104 return inner::__platform_wait_until_impl(addr, old, timeout);
105}
106
107template <typename Clock, typename Dur>
109__platform_wait_until_dispatch(const platform_wait_t* addr, platform_wait_t old,
111 if (!inner::__platform_wait_until_impl(addr, old, inner::to_wait_clock(timeout))) {
112 if (Clock::now() < timeout) {
113 return true;
114 }
115 }
116 return false;
117}
118
119NEFORCE_END_INNER__
121
127
139template <typename Clock, typename Dur>
141 return inner::__platform_wait_until_dispatch(addr, old, timeout);
142}
143 // Futex
145
151
161struct timed_backoff_spin_policy {
162 inner::wait_clock_t::time_point deadline;
163 inner::wait_clock_t::time_point start_time;
164
165 template <typename Clock, typename Dur>
166 timed_backoff_spin_policy(time_point<Clock, Dur> deadline_time = Clock::time_point::max(),
167 time_point<Clock, Dur> start_time_point = Clock::now()) noexcept :
168 deadline(inner::to_wait_clock(deadline_time)),
169 start_time(inner::to_wait_clock(start_time_point)) {}
170
171 bool operator()() const noexcept {
172 const auto now = inner::wait_clock_t::now();
173 if (deadline <= now) {
174 return false;
175 }
176
177 const auto elapsed = now - start_time;
178 if (elapsed > 128_ms) {
179 this_thread::sleep_for(64_ms);
180 } else if (elapsed > 64_us) {
181 this_thread::sleep_for(elapsed / 2);
182 } else if (elapsed > 4_us) {
183 this_thread::yield();
184 } else {
185 return false;
186 }
187 return true;
188 }
189};
190
192NEFORCE_BEGIN_INNER__
193
200struct timed_waiter_pool : waiter_pool_base {
210 template <typename Clock, typename Dur>
211 bool do_wait_until(platform_wait_t* addr, platform_wait_t old, const time_point<Clock, Dur>& timeout) {
212 return _NEFORCE futex_wait_until(addr, old, timeout);
213 }
214};
215
223template <typename EntersWait>
224struct timed_waiter : waiter_base<timed_waiter_pool> {
225 using base_type = waiter_base<timed_waiter_pool>;
226
227private:
228 template <bool Wait = EntersWait::value, enable_if_t<Wait, int> = 0>
229 NEFORCE_ALWAYS_INLINE void enter() const noexcept {
230 waiter_.waiter_enter_wait();
231 }
232 template <bool Wait = EntersWait::value, enable_if_t<!Wait, int> = 0>
233 NEFORCE_ALWAYS_INLINE void enter() const noexcept {}
234
235 template <bool Wait = EntersWait::value, enable_if_t<Wait, int> = 0>
236 NEFORCE_ALWAYS_INLINE void leave() const noexcept {
237 waiter_.waiter_leave_wait();
238 }
239 template <bool Wait = EntersWait::value, enable_if_t<!Wait, int> = 0>
240 NEFORCE_ALWAYS_INLINE void leave() const noexcept {}
241
242public:
248 template <typename T>
249 explicit timed_waiter(const T* addr) noexcept :
250 base_type(addr) {
251 enter();
252 }
253
257 ~timed_waiter() { leave(); }
258
270 template <typename T, typename Func, typename Clock, typename Dur>
271 bool waiter_do_wait_until_v(T old, Func func, const time_point<Clock, Dur>& timeout) noexcept {
272 platform_wait_t value;
273 if (base_type::waiter_do_spin(old, _NEFORCE move(func), value, timed_backoff_spin_policy(timeout))) {
274 return true;
275 }
276 return base_type::waiter_.do_wait_until(base_type::addr_, value, timeout);
277 }
278
289 template <typename Pred, typename Clock, typename Dur>
290 bool waiter_do_wait_until(Pred pred, platform_wait_t value, const time_point<Clock, Dur>& timeout) noexcept {
291 for (auto now = Clock::now(); now < timeout; now = Clock::now()) {
292 if (base_type::waiter_.do_wait_until(base_type::addr_, value, timeout) && pred()) {
293 return true;
294 }
295 if (base_type::waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout, now))) {
296 return true;
297 }
298 }
299 return false;
300 }
301
311 template <typename Pred, typename Clock, typename Dur>
312 bool waiter_do_wait_until(Pred pred, const time_point<Clock, Dur>& timeout) noexcept {
313 platform_wait_t value;
314 if (this->waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout))) {
315 return true;
316 }
317 return this->waiter_do_wait_until(pred, value, timeout);
318 }
319
331 template <typename T, typename Func, typename Rep, typename Period>
332 bool waiter_do_wait_for_v(T old, Func func, const duration<Rep, Period>& rt) noexcept {
333 platform_wait_t value;
334 if (base_type::waiter_do_spin_v(old, _NEFORCE move(func), value)) {
335 return true;
336 }
337 if (!rt.count()) {
338 return false;
339 }
340 auto rtc = ceil<wait_clock_t::duration>(rt);
341 return base_type::waiter_.do_wait_until(base_type::addr_, value, steady_clock::now() + rtc);
342 }
343
353 template <typename Pred, typename Rep, typename Period>
354 bool waiter_do_wait_for(Pred pred, const duration<Rep, Period>& rt) noexcept {
355 platform_wait_t value;
356 if (base_type::waiter_do_spin(pred, value)) {
357 return true;
358 }
359 if (!rt.count()) {
360 return false;
361 }
362 auto rtc = ceil<wait_clock_t::duration>(rt);
363 return this->waiter_do_wait_until(pred, value, steady_clock::now() + rtc);
364 }
365};
366
368using enters_timed_wait = timed_waiter<true_type>;
369
371using bare_timed_wait = timed_waiter<false_type>;
372
373NEFORCE_END_INNER__
375
390template <typename T, typename Func, typename Clock, typename Dur>
391bool atomic_wait_address_until_v(const T* addr, T&& old, Func&& func, const time_point<Clock, Dur>& timeout) noexcept {
392 inner::enters_timed_wait waiter{addr};
393 return waiter.waiter_do_wait_until_v(old, func, timeout);
394}
395
409template <typename T, typename Pred, typename Clock, typename Dur>
410bool atomic_wait_address_until(const T* addr, Pred pred, const time_point<Clock, Dur>& timeout) noexcept {
411 inner::enters_timed_wait waiter{addr};
412 return waiter.waiter_do_wait_until(pred, timeout);
413}
414
427template <typename Pred, typename Clock, typename Dur>
428bool atomic_wait_address_until(const platform_wait_t* addr, Pred pred, const time_point<Clock, Dur>& timeout) noexcept {
429 inner::bare_timed_wait waiter{addr};
430 return waiter.waiter_do_wait_until(pred, timeout);
431}
432
447template <typename T, typename Func, typename Rep, typename Period>
448bool atomic_wait_address_for_v(const T* addr, T&& old, Func&& func, const duration<Rep, Period>& rt) noexcept {
449 inner::enters_timed_wait waiter{addr};
450 return waiter.waiter_do_wait_for_v(old, func, rt);
451}
452
466template <typename T, typename Pred, typename Rep, typename Period>
467bool atomic_wait_address_for(const T* addr, Pred pred, const duration<Rep, Period>& rt) noexcept {
468 inner::enters_timed_wait waiter{addr};
469 return waiter.waiter_do_wait_for(pred, rt);
470}
471
484template <typename Pred, typename Rep, typename Period>
485bool atomic_wait_address_for(const platform_wait_t* addr, Pred pred, const duration<Rep, Period>& rt) noexcept {
486 inner::bare_timed_wait waiter{addr};
487 return waiter.waiter_do_wait_for(pred, rt);
488}
489 // AtomicOperations
491 // AsyncComponents
493
494NEFORCE_END_NAMESPACE__
495#endif // NEFORCE_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
原子等待/通知机制
时钟类型
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)
持续时间类型转换
void NEFORCE_API futex_wait(void *addr, platform_wait_t value) noexcept
无限期等待FUTEX
int platform_wait_t
平台等待类型别名
bool futex_wait_until(const platform_wait_t *addr, platform_wait_t old, const time_point< Clock, Dur > &timeout)
FUTEX定时等待函数
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 decimal_t ceil(const decimal_t x) noexcept
向上取整
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, 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 _NEFORCE time_point< steady_clock, Dur > &tp)
将稳定时钟转为系统时钟
static time_point now() noexcept
获取当前时间点
时间点类模板