MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
stop_token.hpp
浏览该文件的文档.
1#ifndef MSTL_CORE_ASYNC_STOP_TOKEN_HPP__
2#define MSTL_CORE_ASYNC_STOP_TOKEN_HPP__
3
10
16
22
23class stop_source;
24
25
32class stop_token {
33private:
40 struct stop_callback_node {
41 using callback_type = void(stop_callback_node*)
42#ifdef MSTL_STANDARD_17__
43 noexcept
44#endif
45 ;
46
47 callback_type* callback;
48 stop_callback_node* prev = nullptr;
49 stop_callback_node* next = nullptr;
50 bool* destroyed = nullptr;
51 binary_semaphore done_semaphore{0};
52
57 explicit stop_callback_node(callback_type* cb)
58 : callback(cb) {}
59
63 void run() noexcept {
64 callback(this);
65 }
66 };
67
74 struct stop_state {
75 using value_type = uint32_t;
76 static constexpr value_type stop_requested_bit = 1;
77 static constexpr value_type locked_bit = 2;
78 static constexpr value_type ssrc_counter_inc = 4;
79
80 atomic<value_type> owners{1};
81 atomic<value_type> value{ssrc_counter_inc};
82 stop_callback_node* head = nullptr;
83 thread::id requester_thread_id;
84
85 stop_state() = default;
86
91 bool stop_possible() noexcept {
92 return value.load(memory_order_acquire) & ~locked_bit;
93 }
94
99 bool stop_requested() noexcept {
100 return value.load(memory_order_acquire) & stop_requested_bit;
101 }
102
106 void add_owner() noexcept {
107 owners.fetch_add(1, memory_order_relaxed);
108 }
109
114 void release_ownership() noexcept {
115 if (owners.fetch_sub(1, memory_order_acq_rel) == 1)
116 delete this;
117 }
118
122 void add_stop_source() noexcept {
123 value.fetch_add(ssrc_counter_inc, memory_order_relaxed);
124 }
125
129 void remove_stop_source() noexcept {
130 value.fetch_sub(ssrc_counter_inc, memory_order_release);
131 }
132
136 void lock() noexcept {
137 auto old_value = value.load(memory_order_relaxed);
138 while (!try_lock(old_value, memory_order_relaxed)) { }
139 }
140
144 void unlock() noexcept {
145 value.fetch_sub(locked_bit, memory_order_release);
146 }
147
154 bool request_stop() noexcept {
155 auto old_value = value.load(memory_order_acquire);
156 do {
157 if (old_value & stop_requested_bit) {
158 return false;
159 }
160 } while (!try_lock_and_stop(old_value));
161
162 requester_thread_id = this_thread::id();
163
164 while (head) {
165 bool last_callback;
166 stop_callback_node* callback_node = head;
167 head = head->next;
168 if (head) {
169 head->prev = nullptr;
170 last_callback = false;
171 } else {
172 last_callback = true;
173 }
174 unlock();
175
176 bool destroyed = false;
177 callback_node->destroyed = &destroyed;
178 callback_node->run();
179 if (!destroyed) {
180 callback_node->destroyed = nullptr;
181 callback_node->done_semaphore.release();
182 }
183
184 if (last_callback) return true;
185 lock();
186 }
187 unlock();
188 return true;
189 }
190
198 bool register_callback(stop_callback_node* callback_node) noexcept {
199 auto old_value = value.load(memory_order_acquire);
200 do {
201 if (old_value & stop_requested_bit) {
202 callback_node->run();
203 return false;
204 }
205 if (old_value < ssrc_counter_inc) {
206 return false;
207 }
208 } while (!try_lock(old_value));
209
210 callback_node->next = head;
211 if (head) {
212 head->prev = callback_node;
213 }
214 head = callback_node;
215 unlock();
216 return true;
217 }
218
225 void remove_callback(stop_callback_node* callback_node) {
226 lock();
227
228 if (callback_node == head) {
229 head = head->next;
230 if (head)
231 head->prev = nullptr;
232 unlock();
233 return;
234 }
235 if (callback_node->prev) {
236 callback_node->prev->next = callback_node->next;
237 if (callback_node->next)
238 callback_node->next->prev = callback_node->prev;
239 unlock();
240 return;
241 }
242
243 unlock();
244
245 if (requester_thread_id != this_thread::id()) {
246 callback_node->done_semaphore.acquire();
247 return;
248 }
249
250 if (callback_node->destroyed) {
251 *callback_node->destroyed = true;
252 }
253 }
254
261 bool try_lock(value_type& current_value,
262 const memory_order failure_order = memory_order_acquire) noexcept {
263 return do_try_lock(current_value, 0, memory_order_acquire, failure_order);
264 }
265
271 bool try_lock_and_stop(value_type& current_value) noexcept {
272 return do_try_lock(
273 current_value, stop_requested_bit,
275 }
276
280 bool do_try_lock(value_type& current_value, value_type new_bits,
281 const memory_order success_order, const memory_order failure_order) noexcept {
282 if (current_value & locked_bit) {
283 this_thread::relax();
284 current_value = value.load(failure_order);
285 return false;
286 }
287 new_bits |= locked_bit;
288 return value.compare_exchange_weak(
289 current_value, current_value | new_bits,
290 success_order, failure_order);
291 }
292 };
293
300 struct stop_state_reference {
301 private:
302 stop_state* ptr_ = nullptr;
303
304 public:
305 stop_state_reference() = default;
306
311 explicit stop_state_reference(const stop_source& ref)
312 : ptr_(new stop_state()) {}
313
318 stop_state_reference(const stop_state_reference& other) noexcept
319 : ptr_(other.ptr_) {
320 if (ptr_) {
321 ptr_->add_owner();
322 }
323 }
324
329 stop_state_reference(stop_state_reference&& other) noexcept
330 : ptr_(other.ptr_) {
331 other.ptr_ = nullptr;
332 }
333
337 stop_state_reference& operator =(const stop_state_reference& other) noexcept {
338 const auto new_ptr = other.ptr_;
339 if (new_ptr != ptr_) {
340 if (new_ptr) {
341 new_ptr->add_owner();
342 }
343 if (ptr_) {
344 ptr_->release_ownership();
345 }
346 ptr_ = new_ptr;
347 }
348 return *this;
349 }
350
354 stop_state_reference& operator =(stop_state_reference&& other) noexcept {
355 stop_state_reference(move(other)).swap(*this);
356 return *this;
357 }
358
362 ~stop_state_reference() {
363 if (ptr_) {
364 ptr_->release_ownership();
365 }
366 }
367
371 void swap(stop_state_reference& other) noexcept {
372 _MSTL swap(ptr_, other.ptr_);
373 }
374
378 explicit operator bool() const noexcept {
379 return ptr_ != nullptr;
380 }
381
385 stop_state* operator ->() const noexcept {
386 return ptr_;
387 }
388
392 bool operator ==(const stop_state_reference& rhs) const noexcept {
393 return ptr_ == rhs.ptr_;
394 }
395
399 bool operator !=(const stop_state_reference& rhs) const noexcept {
400 return ptr_ != rhs.ptr_;
401 }
402 };
403
404private:
405 stop_state_reference state_ref_;
406
407 friend class stop_source;
408
409 template <typename Callback>
410 friend class stop_callback;
411
416 explicit stop_token(stop_state_reference state_ref) noexcept
417 : state_ref_{move(state_ref)} {}
418
419public:
420 stop_token() noexcept = default;
421 ~stop_token() = default;
422 stop_token(const stop_token&) noexcept = default;
423 stop_token& operator =(const stop_token&) noexcept = default;
424 stop_token(stop_token&&) noexcept = default;
425 stop_token& operator =(stop_token&&) noexcept = default;
426
431 MSTL_NODISCARD bool stop_possible() const noexcept {
432 return static_cast<bool>(state_ref_) && state_ref_->stop_possible();
433 }
434
439 MSTL_NODISCARD bool stop_requested() const noexcept {
440 return static_cast<bool>(state_ref_) && state_ref_->stop_requested();
441 }
442
447 void swap(stop_token& other) noexcept {
448 state_ref_.swap(other.state_ref_);
449 }
450
458 MSTL_NODISCARD bool operator ==(const stop_token& rhs) const {
459 return state_ref_ == rhs.state_ref_;
460 }
461};
462
463
472private:
473 stop_token::stop_state_reference state_ref_;
474
475public:
481 stop_source() : state_ref_(*this) {}
482
489 explicit stop_source(none_t none) noexcept {}
490
495 stop_source(const stop_source& other) noexcept
496 : state_ref_(other.state_ref_) {
497 if (state_ref_) {
498 state_ref_->add_stop_source();
499 }
500 }
501
502 stop_source(stop_source&&) noexcept = default;
503
507 stop_source& operator =(const stop_source& other) noexcept {
508 if (state_ref_ != other.state_ref_) {
509 stop_source sink(move(*this));
510 state_ref_ = other.state_ref_;
511 if (state_ref_) {
512 state_ref_->add_stop_source();
513 }
514 }
515 return *this;
516 }
517
518 stop_source& operator =(stop_source&&) noexcept = default;
519
526 if (state_ref_) {
527 state_ref_->remove_stop_source();
528 }
529 }
530
535 MSTL_NODISCARD bool stop_possible() const noexcept {
536 return static_cast<bool>(state_ref_);
537 }
538
543 MSTL_NODISCARD bool stop_requested() noexcept {
544 return stop_possible() && state_ref_->stop_requested();
545 }
546
553 MSTL_NODISCARD bool request_stop() noexcept {
554 if (stop_possible()) {
555 return state_ref_->request_stop();
556 }
557 return false;
558 }
559
564 MSTL_NODISCARD stop_token get_token() const noexcept {
565 return stop_token{state_ref_};
566 }
567
572 void swap(stop_source& other) noexcept {
573 state_ref_.swap(other.state_ref_);
574 }
575
579 MSTL_NODISCARD bool operator ==(const stop_source& rhs) const noexcept {
580 return state_ref_ == rhs.state_ref_;
581 }
582
586 MSTL_NODISCARD bool operator !=(const stop_source& rhs) const noexcept {
587 return state_ref_ != rhs.state_ref_;
588 }
589};
590
591
603template <typename Callback>
604class MSTL_NODISCARD stop_callback {
605 static_assert(is_nothrow_destructible_v<Callback>, "Callback should be nothrow destructible.");
606 static_assert(is_invocable_v<Callback>, "Callback should be invocable.");
607
608public:
609 using callback_type = Callback;
610
611private:
612 struct callback_impl : stop_token::stop_callback_node {
613 template <typename Cb>
614 explicit callback_impl(Cb&& callback)
615 : stop_callback_node(&execute_callback),
616 callback(forward<Cb>(callback)) {}
617
618 Callback callback;
619
620 static void execute_callback(stop_callback_node* node) noexcept {
621 Callback& cb = static_cast<callback_impl*>(node)->callback;
622 forward<Callback>(cb)();
623 }
624 };
625
626 callback_impl callback_impl;
627 stop_token::stop_state_reference state_ref_;
628
629public:
636 template <typename Cb, enable_if_t<is_constructible_v<Callback, Cb>, int> = 0>
637 explicit stop_callback(const stop_token& token, Cb&& callback)
638 noexcept(is_nothrow_constructible_v<Callback, Cb>)
639 : callback_impl(forward<Cb>(callback)) {
640 if (auto state_ref = token.state_ref_) {
641 if (state_ref->register_callback(&callback_impl)) {
642 state_ref_.swap(state_ref);
643 }
644 }
645 }
646
653 template <typename Cb, enable_if_t<is_constructible_v<Callback, Cb>, int> = 0>
654 explicit stop_callback(stop_token&& token, Cb&& callback)
655 noexcept(is_nothrow_constructible_v<Callback, Cb>)
656 : callback_impl(forward<Cb>(callback)) {
657 if (auto& state_ref = token.state_ref_) {
658 if (state_ref->register_callback(&callback_impl)) {
659 state_ref_.swap(state_ref);
660 }
661 }
662 }
663
664 stop_callback(const stop_callback&) = delete;
665 stop_callback& operator =(const stop_callback&) = delete;
667 stop_callback& operator =(stop_callback&&) = delete;
668
675 if (state_ref_) {
676 state_ref_->remove_callback(&callback_impl);
677 }
678 }
679};
680
681#ifdef MSTL_SUPPORT_DEDUCTION_GUIDES__
682template <typename Callback>
684#endif
685 // StopTokens
687
689#endif // MSTL_CORE_ASYNC_STOP_TOKEN_HPP__
MSTL原子类型完整实现
void release(const platform_wait_t update=1) noexcept
释放信号量
void acquire() noexcept
获取信号量
锁管理器模板
停止回调类模板
stop_callback(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 >)
右值构造函数
MSTL_NODISCARD bool stop_requested() noexcept
检查是否已请求停止
stop_source(stop_source &&) noexcept=default
移动构造函数
stop_source(none_t none) noexcept
构造函数
stop_source()
默认构造函数
MSTL_NODISCARD stop_token get_token() const noexcept
获取停止令牌
void swap(stop_source &other) noexcept
交换两个停止源
stop_source(const stop_source &other) noexcept
拷贝构造函数
MSTL_NODISCARD bool request_stop() noexcept
请求停止
MSTL_NODISCARD bool stop_possible() const noexcept
检查是否具有停止能力
停止令牌类
stop_token() noexcept=default
默认构造函数
MSTL_NODISCARD bool operator==(const stop_token &rhs) const
相等比较运算符
void swap(stop_token &other) noexcept
交换两个停止令牌
MSTL_NODISCARD bool stop_possible() const noexcept
检查是否可能收到停止请求
MSTL_NODISCARD bool stop_requested() const noexcept
检查是否已收到停止请求
MSTL_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
unsigned int uint32_t
32位无符号整数类型
bool operator!=(const function< Res(Args...)> &f, nullptr_t null) noexcept
不等于空指针比较
bool operator==(const function< Res(Args...)> &f, nullptr_t null) noexcept
等于空指针比较
constexpr Iterator prev(Iterator iter, iter_difference_t< Iterator > n=-1)
获取迭代器的前一个位置
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
MSTL_INLINE17 constexpr auto memory_order_release
释放内存顺序常量
MSTL_INLINE17 constexpr auto memory_order_acq_rel
获取-释放内存顺序常量
MSTL_INLINE17 constexpr auto memory_order_relaxed
宽松内存顺序常量
MSTL_INLINE17 constexpr auto memory_order_acquire
获取内存顺序常量
memory_order
内存顺序
MSTL_INLINE17 constexpr try_lock_tag try_lock
尝试锁定标签实例
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
MSTL_INLINE17 constexpr none_t none
默认空表示
MSTL_NODISCARD constexpr reference_wrapper< T > ref(T &val) noexcept
创建引用包装器
counting_semaphore< 1 > binary_semaphore
二元信号量
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
void swap()=delete
删除无参数的swap重载
MSTL空状态类型
MSTL信号量支持
通用原子类型模板
T load(const memory_order mo=memory_order_seq_cst) const noexcept
原子加载操作
bool compare_exchange_weak(T &expected, T desired, const memory_order success, const memory_order failure) noexcept
弱比较交换操作
空状态类型
线程唯一标识符类
MSTL线程支持