1#ifndef NEFORCE_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
2#define NEFORCE_CORE_ASYNC_ATOMIC_TIMED_WAIT_HPP__
13NEFORCE_BEGIN_NAMESPACE__
24using wait_clock_t = steady_clock;
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);
51template <
typename Dur>
52wait_clock_t::time_point to_wait_clock(
const time_point<wait_clock_t, Dur>& time_point)
noexcept {
53 return ceil<wait_clock_t::duration>(time_point);
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());
72 futex_wait(
const_cast<void*
>(
static_cast<const void*
>(addr)), old);
76 const auto now = wait_clock_t::now();
82 const auto sec = _NEFORCE time_cast<seconds>(dur);
83 const auto ns = _NEFORCE time_cast<nanoseconds>(dur - sec);
85 return _NEFORCE
futex_wait_until(
const_cast<void*
>(
static_cast<const void*
>(addr)), old,
true, sec.count(),
89template <
typename Clock,
typename Dur>
90enable_if_t<is_same_v<wait_clock_t, Clock>,
bool>
91__platform_wait_until_dispatch(
const platform_wait_t* addr, platform_wait_t old,
92 const time_point<Clock, Dur>& timeout) {
93 return inner::__platform_wait_until_impl(addr, old, timeout);
96template <
typename Clock,
typename Dur>
97enable_if_t<!is_same_v<wait_clock_t, Clock>,
bool>
98__platform_wait_until_dispatch(
const platform_wait_t* addr, platform_wait_t old,
99 const time_point<Clock, Dur>& timeout) {
100 if (!inner::__platform_wait_until_impl(addr, old, inner::to_wait_clock(timeout))) {
101 if (Clock::now() < timeout) {
128template <
typename Clock,
typename Dur>
130 return inner::__platform_wait_until_dispatch(addr, old,
timeout);
150struct timed_backoff_spin_policy {
151 inner::wait_clock_t::time_point deadline;
152 inner::wait_clock_t::time_point start_time;
154 template <
typename Clock,
typename Dur>
157 deadline(inner::to_wait_clock(deadline_time)),
158 start_time(inner::to_wait_clock(start_time_point)) {}
160 bool operator()()
const noexcept {
161 const auto now = inner::wait_clock_t::now();
162 if (deadline <= now) {
166 const auto elapsed = now - start_time;
167 if (elapsed > 128_ms) {
169 }
else if (elapsed > 64_us) {
171 }
else if (elapsed > 4_us) {
189struct timed_waiter_pool : waiter_pool_base {
199 template <
typename Clock,
typename Dur>
212template <
typename EntersWait>
213struct timed_waiter : waiter_base<timed_waiter_pool> {
214 using base_type = waiter_base<timed_waiter_pool>;
217 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
218 NEFORCE_ALWAYS_INLINE
void enter() const noexcept {
219 waiter_.waiter_enter_wait();
221 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
222 NEFORCE_ALWAYS_INLINE
void enter() const noexcept {}
224 template <
bool Wait = EntersWait::value, enable_if_t<Wait,
int> = 0>
225 NEFORCE_ALWAYS_INLINE
void leave() const noexcept {
226 waiter_.waiter_leave_wait();
228 template <
bool Wait = EntersWait::value, enable_if_t<!Wait,
int> = 0>
229 NEFORCE_ALWAYS_INLINE
void leave() const noexcept {}
237 template <
typename T>
238 explicit timed_waiter(
const T* addr) noexcept :
246 ~timed_waiter() { leave(); }
259 template <
typename T,
typename Func,
typename Clock,
typename Dur>
260 bool waiter_do_wait_until_v(T old, Func func,
const time_point<Clock, Dur>& timeout)
noexcept {
262 if (base_type::waiter_do_spin(old, _NEFORCE
move(func), value, timed_backoff_spin_policy(timeout))) {
265 return base_type::waiter_.do_wait_until(base_type::addr_, value, timeout);
278 template <
typename Pred,
typename Clock,
typename Dur>
279 bool waiter_do_wait_until(Pred pred, platform_wait_t value,
const time_point<Clock, Dur>& timeout)
noexcept {
280 for (
auto now = Clock::now(); now <
timeout; now = Clock::now()) {
281 if (base_type::waiter_.do_wait_until(base_type::addr_, value, timeout) && pred()) {
284 if (base_type::waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout, now))) {
300 template <
typename Pred,
typename Clock,
typename Dur>
301 bool waiter_do_wait_until(Pred pred,
const time_point<Clock, Dur>& timeout)
noexcept {
303 if (this->waiter_do_spin(pred, value, timed_backoff_spin_policy(timeout))) {
306 return this->waiter_do_wait_until(pred, value, timeout);
320 template <
typename T,
typename Func,
typename Rep,
typename Period>
321 bool waiter_do_wait_for_v(T old, Func func,
const duration<Rep, Period>& rt)
noexcept {
323 if (base_type::waiter_do_spin_v(old, _NEFORCE
move(func), value)) {
329 auto rtc = ceil<wait_clock_t::duration>(rt);
330 return base_type::waiter_.do_wait_until(base_type::addr_, value, steady_clock::now() + rtc);
342 template <
typename Pred,
typename Rep,
typename Period>
343 bool waiter_do_wait_for(Pred pred,
const duration<Rep, Period>& rt)
noexcept {
345 if (base_type::waiter_do_spin(pred, value)) {
351 auto rtc = ceil<wait_clock_t::duration>(rt);
352 return this->waiter_do_wait_until(pred, value, steady_clock::now() + rtc);
357using enters_timed_wait = timed_waiter<true_type>;
360using bare_timed_wait = timed_waiter<false_type>;
379template <
typename T,
typename Func,
typename Clock,
typename Dur>
381 inner::enters_timed_wait waiter{addr};
382 return waiter.waiter_do_wait_until_v(old, func,
timeout);
398template <
typename T,
typename Pred,
typename Clock,
typename Dur>
400 inner::enters_timed_wait waiter{addr};
401 return waiter.waiter_do_wait_until(pred,
timeout);
416template <
typename Pred,
typename Clock,
typename Dur>
418 inner::bare_timed_wait waiter{addr};
419 return waiter.waiter_do_wait_until(pred,
timeout);
436template <
typename T,
typename Func,
typename Rep,
typename Period>
438 inner::enters_timed_wait waiter{addr};
439 return waiter.waiter_do_wait_for_v(old, func, rt);
455template <
typename T,
typename Pred,
typename Rep,
typename Period>
457 inner::enters_timed_wait waiter{addr};
458 return waiter.waiter_do_wait_for(pred, rt);
473template <
typename Pred,
typename Rep,
typename Period>
475 inner::bare_timed_wait waiter{addr};
476 return waiter.waiter_do_wait_for(pred, rt);
483NEFORCE_END_NAMESPACE__
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_until_v(const T *addr, T &&old, Func &&func, const time_point< Clock, Dur > &timeout) noexcept
基于值的原子定时等待(绝对时间)
bool atomic_wait_address_for(const T *addr, Pred pred, const duration< Rep, Period > &rt) noexcept
基于谓词的原子定时等待(相对时间)
long platform_wait_t
平台等待类型别名
bool futex_wait_until(const platform_wait_t *addr, platform_wait_t old, const time_point< Clock, Dur > &timeout)
FUTEX定时等待函数
void futex_wait(void *addr, platform_wait_t value) noexcept
无限期等待FUTEX
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
void yield() noexcept
让出当前线程的时间片
void sleep_for(const duration< Rep, Period > time)
使当前线程睡眠指定时间