NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
stop_token.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_ASYNC_STOP_TOKEN_HPP__
2#define NEFORCE_CORE_ASYNC_STOP_TOKEN_HPP__
3
10
15NEFORCE_BEGIN_NAMESPACE__
16
22
28
29class stop_source;
30
31
38class stop_token {
39private:
46 struct stop_callback_node {
47 using callback_type = void(stop_callback_node*)
48#ifdef NEFORCE_STANDARD_17
49 noexcept
50#endif
51 ;
52
53 callback_type* callback;
54 stop_callback_node* prev = nullptr;
55 stop_callback_node* next = nullptr;
56 bool* destroyed = nullptr;
57 binary_semaphore done_semaphore{0};
58
63 explicit stop_callback_node(callback_type* cb) :
64 callback(cb) {}
65
69 void run() noexcept { callback(this); }
70 };
71
78 struct stop_state {
79 using value_type = uint32_t;
80 static constexpr value_type stop_requested_bit = 1;
81 static constexpr value_type locked_bit = 2;
82 static constexpr value_type ssrc_counter_inc = 4;
83
84 atomic<value_type> owners{1};
85 atomic<value_type> value{ssrc_counter_inc};
86 stop_callback_node* head = nullptr;
87 thread::id requester_thread_id;
88
89 stop_state() = default;
90
95 bool stop_possible() noexcept { return (value.load(memory_order_acquire) & ~locked_bit) != 0U; }
96
101 bool stop_requested() noexcept { return (value.load(memory_order_acquire) & stop_requested_bit) != 0U; }
102
106 void add_owner() noexcept { owners.fetch_add(1, memory_order_relaxed); }
107
112 void release_ownership() noexcept {
113 if (owners.fetch_sub(1, memory_order_acq_rel) == 1) {
114 delete this;
115 }
116 }
117
121 void add_stop_source() noexcept { value.fetch_add(ssrc_counter_inc, memory_order_relaxed); }
122
126 void remove_stop_source() noexcept { value.fetch_sub(ssrc_counter_inc, memory_order_release); }
127
131 void lock() noexcept {
132 auto old_value = value.load(memory_order_relaxed);
133 while (!try_lock(old_value, memory_order_relaxed)) {
134 }
135 }
136
140 void unlock() noexcept { value.fetch_sub(locked_bit, memory_order_release); }
141
148 bool request_stop() noexcept {
149 auto old_value = value.load(memory_order_acquire);
150 do {
151 if ((old_value & stop_requested_bit) != 0U) {
152 return false;
153 }
154 } while (!try_lock_and_stop(old_value));
155
156 requester_thread_id = this_thread::id();
157
158 while (head != nullptr) {
159 bool last_callback = false;
160 stop_callback_node* callback_node = head;
161 head = head->next;
162 if (head != nullptr) {
163 head->prev = nullptr;
164 last_callback = false;
165 } else {
166 last_callback = true;
167 }
168 unlock();
169
170 bool destroyed = false;
171 callback_node->destroyed = &destroyed;
172 callback_node->run();
173 if (!destroyed) {
174 callback_node->destroyed = nullptr;
175 callback_node->done_semaphore.release();
176 }
177
178 if (last_callback) {
179 return true;
180 }
181 lock();
182 }
183 unlock();
184 return true;
185 }
186
194 bool register_callback(stop_callback_node* callback_node) noexcept {
195 auto old_value = value.load(memory_order_acquire);
196 do {
197 if ((old_value & stop_requested_bit) != 0U) {
198 callback_node->run();
199 return false;
200 }
201 if (old_value < ssrc_counter_inc) {
202 return false;
203 }
204 } while (!try_lock(old_value));
205
206 callback_node->next = head;
207 if (head != nullptr) {
208 head->prev = callback_node;
209 }
210 head = callback_node;
211 unlock();
212 return true;
213 }
214
221 void remove_callback(stop_callback_node* callback_node) {
222 lock();
223
224 if (callback_node == head) {
225 head = head->next;
226 if (head != nullptr) {
227 head->prev = nullptr;
228 }
229 unlock();
230 return;
231 }
232 if (callback_node->prev != nullptr) {
233 callback_node->prev->next = callback_node->next;
234 if (callback_node->next != nullptr) {
235 callback_node->next->prev = callback_node->prev;
236 }
237 unlock();
238 return;
239 }
240
241 unlock();
242
243 if (requester_thread_id != this_thread::id()) {
244 callback_node->done_semaphore.acquire();
245 return;
246 }
247
248 if (callback_node->destroyed != nullptr) {
249 *callback_node->destroyed = true;
250 }
251 }
252
259 bool try_lock(value_type& current_value, const memory_order failure_order = memory_order_acquire) noexcept {
260 return do_try_lock(current_value, 0, memory_order_acquire, failure_order);
261 }
262
268 bool try_lock_and_stop(value_type& current_value) noexcept {
269 return do_try_lock(current_value, stop_requested_bit, memory_order_acq_rel, memory_order_acquire);
270 }
271
275 bool do_try_lock(value_type& current_value, value_type new_bits, const memory_order success_order,
276 const memory_order failure_order) noexcept {
277 if ((current_value & locked_bit) != 0U) {
278 this_thread::relax();
279 current_value = value.load(failure_order);
280 return false;
281 }
282 new_bits |= locked_bit;
283 return value.compare_exchange_weak(current_value, current_value | new_bits, success_order, failure_order);
284 }
285 };
286
293 struct stop_state_reference {
294 private:
295 stop_state* ptr_ = nullptr;
296
297 public:
298 stop_state_reference() = default;
299
304 explicit stop_state_reference(const stop_source& ref) :
305 ptr_(new stop_state()) {}
306
311 stop_state_reference(const stop_state_reference& other) noexcept :
312 ptr_(other.ptr_) {
313 if (ptr_ != nullptr) {
314 ptr_->add_owner();
315 }
316 }
317
322 stop_state_reference(stop_state_reference&& other) noexcept :
323 ptr_(other.ptr_) {
324 other.ptr_ = nullptr;
325 }
326
330 stop_state_reference& operator=(const stop_state_reference& other) noexcept {
331 if (addressof(other) == this) {
332 return *this;
333 }
334 auto* const new_ptr = other.ptr_;
335 if (new_ptr != ptr_) {
336 if (new_ptr != nullptr) {
337 new_ptr->add_owner();
338 }
339 if (ptr_ != nullptr) {
340 ptr_->release_ownership();
341 }
342 ptr_ = new_ptr;
343 }
344 return *this;
345 }
346
350 stop_state_reference& operator=(stop_state_reference&& other) noexcept {
351 if (addressof(other) == this) {
352 return *this;
353 }
354 stop_state_reference(move(other)).swap(*this);
355 return *this;
356 }
357
361 ~stop_state_reference() {
362 if (ptr_ != nullptr) {
363 ptr_->release_ownership();
364 }
365 }
366
370 void swap(stop_state_reference& other) noexcept { _NEFORCE swap(ptr_, other.ptr_); }
371
375 explicit operator bool() const noexcept { return ptr_ != nullptr; }
376
380 stop_state* operator->() const noexcept { return ptr_; }
381
385 bool operator==(const stop_state_reference& rhs) const noexcept { return ptr_ == rhs.ptr_; }
386
390 bool operator!=(const stop_state_reference& rhs) const noexcept { return ptr_ != rhs.ptr_; }
391 };
392
393private:
394 stop_state_reference state_ref_;
395
396 friend class stop_source;
397
398 template <typename Callback>
399 friend class stop_callback;
400
405 explicit stop_token(stop_state_reference state_ref) noexcept :
406 state_ref_{move(state_ref)} {}
407
408public:
409 stop_token() noexcept = default;
410 ~stop_token() = default;
411 stop_token(const stop_token&) noexcept = default;
412 stop_token& operator=(const stop_token&) noexcept = default;
413 stop_token(stop_token&&) noexcept = default;
414 stop_token& operator=(stop_token&&) noexcept = default;
415
420 NEFORCE_NODISCARD bool stop_possible() const noexcept {
421 return static_cast<bool>(state_ref_) && state_ref_->stop_possible();
422 }
423
428 NEFORCE_NODISCARD bool stop_requested() const noexcept {
429 return static_cast<bool>(state_ref_) && state_ref_->stop_requested();
430 }
431
436 void swap(stop_token& other) noexcept { state_ref_.swap(other.state_ref_); }
437
445 NEFORCE_NODISCARD bool operator==(const stop_token& rhs) const { return state_ref_ == rhs.state_ref_; }
446};
447
448
457private:
458 stop_token::stop_state_reference state_ref_;
459
460public:
467 state_ref_(*this) {}
468
475 explicit stop_source(none_t none) noexcept {}
476
481 stop_source(const stop_source& other) noexcept :
482 state_ref_(other.state_ref_) {
483 if (state_ref_) {
484 state_ref_->add_stop_source();
485 }
486 }
487
488 stop_source(stop_source&&) noexcept = default;
489
493 stop_source& operator=(const stop_source& other) noexcept {
494 if (state_ref_ != other.state_ref_) {
495 stop_source sink(move(*this));
496 state_ref_ = other.state_ref_;
497 if (state_ref_) {
498 state_ref_->add_stop_source();
499 }
500 }
501 return *this;
502 }
503
504 stop_source& operator=(stop_source&&) noexcept = default;
505
512 if (state_ref_) {
513 state_ref_->remove_stop_source();
514 }
515 }
516
521 NEFORCE_NODISCARD bool stop_possible() const noexcept { return static_cast<bool>(state_ref_); }
522
527 NEFORCE_NODISCARD bool stop_requested() noexcept { return stop_possible() && state_ref_->stop_requested(); }
528
535 NEFORCE_NODISCARD bool request_stop() noexcept {
536 if (stop_possible()) {
537 return state_ref_->request_stop();
538 }
539 return false;
540 }
541
546 NEFORCE_NODISCARD stop_token get_token() const noexcept { return stop_token{state_ref_}; }
547
552 void swap(stop_source& other) noexcept { state_ref_.swap(other.state_ref_); }
553
557 NEFORCE_NODISCARD bool operator==(const stop_source& rhs) const noexcept { return state_ref_ == rhs.state_ref_; }
558
562 NEFORCE_NODISCARD bool operator!=(const stop_source& rhs) const noexcept { return state_ref_ != rhs.state_ref_; }
563};
564
565
577template <typename Callback>
578class NEFORCE_NODISCARD stop_callback {
579 static_assert(is_nothrow_destructible_v<Callback>, "Callback should be nothrow destructible.");
580 static_assert(is_invocable_v<Callback>, "Callback should be invocable.");
581
582public:
583 using callback_type = Callback;
584
585private:
586 struct callback_impl : stop_token::stop_callback_node {
587 template <typename Cb>
588 explicit callback_impl(Cb&& callback) :
589 stop_callback_node(&execute_callback),
590 callback(forward<Cb>(callback)) {}
591
592 Callback callback;
593
594 static void execute_callback(stop_callback_node* node) noexcept {
595 Callback& cb = static_cast<callback_impl*>(node)->callback;
596 forward<Callback>(cb)();
597 }
598 };
599
600 callback_impl callback_impl;
601 stop_token::stop_state_reference state_ref_;
602
603public:
610 template <typename Cb, enable_if_t<is_constructible_v<Callback, Cb>, int> = 0>
611 explicit stop_callback(const stop_token& token, Cb&& callback) noexcept(is_nothrow_constructible_v<Callback, Cb>) :
612 callback_impl(forward<Cb>(callback)) {
613 if (auto state_ref = token.state_ref_) {
614 if (state_ref->register_callback(&callback_impl)) {
615 state_ref_.swap(state_ref);
616 }
617 }
618 }
619
626 template <typename Cb, enable_if_t<is_constructible_v<Callback, Cb>, int> = 0>
627 explicit stop_callback(stop_token&& token, Cb&& callback) noexcept(is_nothrow_constructible_v<Callback, Cb>) :
628 callback_impl(forward<Cb>(callback)) {
629 if (auto& state_ref = token.state_ref_) {
630 if (state_ref->register_callback(&callback_impl)) {
631 state_ref_.swap(state_ref);
632 }
633 }
634 }
635
636 stop_callback(const stop_callback&) = delete;
640
647 if (state_ref_) {
648 state_ref_->remove_callback(&callback_impl);
649 }
650 }
651};
652
653#ifdef NEFORCE_STANDARD_17
654template <typename Callback>
656#endif
657 // StopTokens
659 // AsyncComponents
661
662NEFORCE_END_NAMESPACE__
663#endif // NEFORCE_CORE_ASYNC_STOP_TOKEN_HPP__
原子类型完整实现
void acquire() noexcept
获取信号量
void release(const platform_wait_t update=1) noexcept
释放信号量
锁管理器模板
停止回调类模板
stop_callback(const stop_callback &)=delete
禁止拷贝构造
stop_callback & operator=(const stop_callback &)=delete
禁止拷贝赋值
Callback callback_type
回调函数类型
~stop_callback()
析构函数
stop_callback(stop_callback &&)=delete
禁止移动构造
stop_callback(const stop_token &token, Cb &&callback) noexcept(is_nothrow_constructible_v< Callback, Cb >)
左值构造函数
stop_callback(stop_token &&token, Cb &&callback) noexcept(is_nothrow_constructible_v< Callback, Cb >)
右值构造函数
stop_callback & operator=(stop_callback &&)=delete
禁止移动赋值
stop_source(stop_source &&) noexcept=default
移动构造函数
stop_source(none_t none) noexcept
构造函数
bool stop_possible() const noexcept
检查是否具有停止能力
stop_source()
默认构造函数
void swap(stop_source &other) noexcept
交换两个停止源
bool operator==(const stop_source &rhs) const noexcept
相等比较运算符
stop_source(const stop_source &other) noexcept
拷贝构造函数
bool stop_requested() noexcept
检查是否已请求停止
stop_source & operator=(stop_source &&) noexcept=default
移动赋值运算符
bool operator!=(const stop_source &rhs) const noexcept
不等比较运算符
bool request_stop() noexcept
请求停止
stop_token get_token() const noexcept
获取停止令牌
停止令牌类
stop_token() noexcept=default
默认构造函数
void swap(stop_token &other) noexcept
交换两个停止令牌
bool stop_possible() const noexcept
检查是否可能收到停止请求
stop_token & operator=(const stop_token &) noexcept=default
拷贝赋值运算符
bool operator==(const stop_token &rhs) const
相等比较运算符
bool stop_requested() const noexcept
检查是否已收到停止请求
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
constexpr T * addressof(T &x) noexcept
获取对象的地址
unsigned int uint32_t
32位无符号整数类型
bool operator!=(const function< Res(Args...)> &f, nullptr_t np) noexcept
不等于空指针比较
constexpr bool is_invocable_v
is_invocable的便捷变量模板
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr Iterator prev(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的前一个位置
constexpr auto memory_order_release
释放内存顺序常量
constexpr auto memory_order_relaxed
宽松内存顺序常量
constexpr auto memory_order_acquire
获取内存顺序常量
constexpr auto memory_order_acq_rel
获取-释放内存顺序常量
memory_order
内存顺序
constexpr try_lock_tag try_lock
尝试锁定标签实例
constexpr none_t none
默认空表示
constexpr reference_wrapper< T > ref(T &val) noexcept
创建引用包装器
atomic_semaphore< 1 > binary_semaphore
二元信号量
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
void swap()=delete
删除无参数的swap重载
constexpr bool is_nothrow_constructible_v
is_nothrow_constructible的便捷变量模板
constexpr bool is_nothrow_destructible_v
is_nothrow_destructible的便捷变量模板
空状态类型
信号量支持
通用原子类型模板
空状态类型
线程唯一标识符类
线程管理类