NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
hazard_ptr.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_ASYNC_HAZARD_PTR_HPP__
2#define NEFORCE_CORE_ASYNC_HAZARD_PTR_HPP__
3
11
16NEFORCE_BEGIN_NAMESPACE__
17
23
29
32
40struct hazard_pointer_record {
44
45 hazard_pointer_record() = default;
46
51 bool try_acquire() {
52 bool expected = false;
53 return active.compare_exchange_strong(expected, true, memory_order_acquire, memory_order_relaxed);
54 }
55
59 void release() {
60 hazard_ptr.store(nullptr, memory_order_release);
61 active.store(false, memory_order_release);
62 }
63
68 void protect(void* ptr) { hazard_ptr.store(ptr, memory_order_release); }
69
74 NEFORCE_NODISCARD void* get_protected() const { return hazard_ptr.load(memory_order_acquire); }
75};
76
85public:
87
88 virtual ~hazard_pointer_obj_base() = default;
89 virtual void destroy() = 0;
90 NEFORCE_NODISCARD virtual void* get_ptr() const = 0;
91};
92
101template <typename T, typename Deleter = default_deleter<void>>
103 T* ptr;
104 Deleter deleter;
105
106public:
112 explicit hazard_pointer_obj(T* p, Deleter d = Deleter()) :
113 ptr(p),
114 deleter(_NEFORCE move(d)) {}
115
119 void destroy() override { deleter(ptr); }
120
121 NEFORCE_NODISCARD void* get_ptr() const override { return static_cast<void*>(ptr); }
122};
123
130struct retire_list {
132 size_t count{0};
133
134 retire_list() noexcept = default;
135
139 retire_list(retire_list&& other) noexcept :
140 head(other.head),
141 count(other.count) {
142 other.head = nullptr;
143 other.count = 0;
144 }
145
149 retire_list& operator=(retire_list&& other) noexcept {
150 if (addressof(other) == this) {
151 return *this;
152 }
153 clear();
154 head = other.head;
155 count = other.count;
156 other.head = nullptr;
157 other.count = 0;
158 return *this;
159 }
160
161 retire_list(const retire_list&) = delete;
162 retire_list& operator=(const retire_list&) = delete;
163
168
174 obj->next = head;
175 head = obj;
176 ++count;
177 }
178
182 void clear() {
183 while (head != nullptr) {
184 auto* next = head->next;
185 head->destroy();
186 delete head;
187 head = next;
188 }
189 count = 0;
190 }
191};
192
199class hazard_pointer_domain {
200private:
201 atomic<hazard_pointer_record*> head_{nullptr};
202
203 static retire_list& get_thread_retire_list() {
204 thread_local retire_list list;
205 return list;
206 }
207
208 static constexpr size_t RETIRE_THRESHOLD = 100;
209
214 vector<void*> get_hazard_pointers() {
215 vector<void*> hazards;
216 hazard_pointer_record* current = head_.load(memory_order_acquire);
217
218 while (current != nullptr) {
219 if (current->active.load(memory_order_acquire)) {
220 void* ptr = current->get_protected();
221 if (ptr != nullptr) {
222 hazards.push_back(ptr);
223 }
224 }
225 current = current->next.load(memory_order_acquire);
226 }
227
228 return hazards;
229 }
230
237 void scan_and_reclaim() {
238 auto hazards = get_hazard_pointers();
239 _NEFORCE sort(hazards.begin(), hazards.end(), less<void*>());
240
241 auto& thread_list = get_thread_retire_list();
242 hazard_pointer_obj_base* current = thread_list.head;
243 thread_list.head = nullptr;
244 thread_list.count = 0;
245
246 hazard_pointer_obj_base* keep_head = nullptr;
247 size_t keep_count = 0;
248 hazard_pointer_obj_base* destroy_head = nullptr;
249
250 while (current != nullptr) {
251 auto* next = current->next;
252 void* inner_ptr = current->get_ptr();
253
254 if (_NEFORCE binary_search(hazards.begin(), hazards.end(), inner_ptr, less<void*>())) {
255 current->next = keep_head;
256 keep_head = current;
257 ++keep_count;
258 } else {
259 current->next = destroy_head;
260 destroy_head = current;
261 }
262 current = next;
263 }
264
265 while (destroy_head != nullptr) {
266 auto* next = destroy_head->next;
267 destroy_head->destroy();
268 delete destroy_head;
269 destroy_head = next;
270 }
271
272 thread_list.head = keep_head;
273 thread_list.count = keep_count;
274 }
275
276public:
277 hazard_pointer_domain() = default;
278
285 hazard_pointer_record* current = head_.load();
286 while (current != nullptr) {
287 auto* next = current->next.load();
288 delete current;
289 current = next;
290 }
291 }
292
294 hazard_pointer_domain& operator=(const hazard_pointer_domain&) = delete;
295
303 hazard_pointer_record* current = head_.load(memory_order_acquire);
304 while (current != nullptr) {
305 if (current->try_acquire()) {
306 return current;
307 }
308 current = current->next.load(memory_order_acquire);
309 }
310
311 auto* new_record = new hazard_pointer_record();
312 new_record->active.store(true, memory_order_relaxed);
313
314 hazard_pointer_record* old_head = head_.load(memory_order_relaxed);
315 do {
316 new_record->next.store(old_head, memory_order_relaxed);
317 } while (!head_.compare_exchange_weak(old_head, new_record, memory_order_release, memory_order_relaxed));
318
319 return new_record;
320 }
321
331 template <typename T, typename Deleter = default_deleter<T>>
332 void retire(T* ptr, Deleter deleter = Deleter()) {
333 if (!ptr) {
334 return;
335 }
336
337 auto* obj = new hazard_pointer_obj<T, Deleter>(ptr, _NEFORCE move(deleter));
338 get_thread_retire_list().add(obj);
339
340 if (get_thread_retire_list().count >= RETIRE_THRESHOLD) {
341 scan_and_reclaim();
342 }
343 }
344
348 void reclaim() { scan_and_reclaim(); }
349
354 static hazard_pointer_domain& default_domain() {
355 static hazard_pointer_domain domain{};
356 return domain;
357 }
358};
359
360
367class hazard_pointer {
368private:
369 hazard_pointer_record* record_{nullptr};
370 hazard_pointer_domain* domain_{nullptr};
371
372public:
373 hazard_pointer() = default;
374
382 domain_(&domain) {
383 record_ = domain_->acquire_record();
384 }
385
393 if (record_ != nullptr) {
394 record_->release();
395 }
396 }
397
398 hazard_pointer(hazard_pointer&& other) noexcept :
399 record_(other.record_),
400 domain_(other.domain_) {
401 other.record_ = nullptr;
402 other.domain_ = nullptr;
403 }
404
405 hazard_pointer& operator=(hazard_pointer&& other) noexcept {
406 if (addressof(other) == this) {
407 return *this;
408 }
409
411 if (record_ != nullptr) {
412 record_->release();
413 }
414 record_ = other.record_;
415 domain_ = other.domain_;
416 other.record_ = nullptr;
417 other.domain_ = nullptr;
418
419 return *this;
420 }
421
422 hazard_pointer(const hazard_pointer&) = delete;
423 hazard_pointer& operator=(const hazard_pointer&) = delete;
424
433 template <typename T>
434 T* protect(const atomic<T*>& src) {
435 if (!record_) {
436 return nullptr;
437 }
438
439 T* ptr = src.load(memory_order_relaxed);
440 while (true) {
441 record_->protect(ptr);
442 T* ptr2 = src.load(memory_order_acquire);
443 if (ptr == ptr2) {
444 return ptr;
445 }
446 ptr = ptr2;
447 }
448 }
449
457 template <typename T>
458 bool try_protect(T*& ptr, const atomic<T*>& src) {
459 if (!record_) {
460 return false;
461 }
462
463 ptr = src.load(memory_order_relaxed);
464 record_->protect(ptr);
465 T* ptr2 = src.load(memory_order_acquire);
466
467 if (ptr == ptr2) {
468 return true;
469 }
470
471 ptr = ptr2;
472 return false;
473 }
474
480 void reset_protection() noexcept {
481 if (record_ != nullptr) {
482 record_->protect(nullptr);
483 }
484 }
485
490 void swap(hazard_pointer& other) noexcept {
491 _NEFORCE swap(record_, other.record_);
492 _NEFORCE swap(domain_, other.domain_);
493 }
494
499 explicit operator bool() const noexcept { return record_ != nullptr; }
500};
501
510
511
519template <typename T>
520class hazard_pointer_holder {
521private:
522 hazard_pointer hp_;
523 T* ptr_{nullptr};
524
525public:
526 hazard_pointer_holder() = default;
527
533 hp_(domain) {}
534
540 T* protect(const atomic<T*>& src) {
541 ptr_ = hp_.protect(src);
542 return ptr_;
543 }
544
549 T* get() const noexcept { return ptr_; }
550
555 T& operator*() const noexcept { return *ptr_; }
556
561 T* operator->() const noexcept { return ptr_; }
562
567 explicit operator bool() const noexcept { return ptr_ != nullptr; }
568
572 void reset() noexcept {
573 hp_.reset_protection();
574 ptr_ = nullptr;
575 }
576};
577 // HazardPointer
579 // AsyncComponents
581
582NEFORCE_END_NAMESPACE__
583#endif // NEFORCE_CORE_ASYNC_HAZARD_PTR_HPP__
原子类型完整实现
static hazard_pointer_domain & default_domain()
获取默认的险象指针域
void retire(T *ptr, Deleter deleter=Deleter())
退役一个对象
hazard_pointer_record * acquire_record()
获取一个可用的险象指针记录
void reclaim()
手动触发回收
~hazard_pointer_domain()
析构函数
T & operator*() const noexcept
解引用操作符
T * protect(const atomic< T * > &src)
保护原子指针
T * get() const noexcept
获取当前保护的指针
void reset() noexcept
重置持有的指针
T * operator->() const noexcept
箭头操作符
hazard_pointer_holder(hazard_pointer_domain &domain)
构造函数
险象指针对象基类
virtual void * get_ptr() const =0
获取包装的内部指针
virtual void destroy()=0
销毁对象
hazard_pointer_obj_base * next
链表中的下一个对象
险象指针对象模板
hazard_pointer_obj(T *p, Deleter d=Deleter())
构造函数
void destroy() override
销毁对象
void * get_ptr() const override
获取包装的内部指针
险象指针句柄
~hazard_pointer()
析构函数
void swap(hazard_pointer &other) noexcept
交换两个险象指针
bool try_protect(T *&ptr, const atomic< T * > &src)
尝试保护一个原子指针
void reset_protection() noexcept
重置保护
T * protect(const atomic< T * > &src)
保护一个原子指针
hazard_pointer(hazard_pointer_domain &domain)
构造函数
双向链表容器
动态大小数组容器
constexpr void push_back(const T &value)
在末尾拷贝插入元素
智能指针删除器
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr bool binary_search(Iterator first, Iterator last, const T &value)
在有序范围内进行二分查找
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
hazard_pointer make_hazard_pointer(hazard_pointer_domain &domain=hazard_pointer_domain::default_domain())
创建险象指针的辅助函数
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr auto memory_order_release
释放内存顺序常量
constexpr auto memory_order_relaxed
宽松内存顺序常量
constexpr auto memory_order_acquire
获取内存顺序常量
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
void sort(Iterator first, Iterator last, Compare comp)
标准排序
void swap()=delete
删除无参数的swap重载
排序算法
bool load(const memory_order mo=memory_order_seq_cst) const noexcept
原子加载操作
通用原子类型模板
T load(const memory_order mo=memory_order_seq_cst) const noexcept
原子加载操作
void protect(void *ptr)
保护指定的指针
void release()
释放记录
atomic< hazard_pointer_record * > next
链表中的下一个记录
atomic< void * > hazard_ptr
受保护的指针
bool try_acquire()
尝试获取记录的所有权
void * get_protected() const
获取当前保护的指针
atomic< bool > active
记录是否活跃
小于比较仿函数
线程本地退役列表
size_t count
列表大小
void add(hazard_pointer_obj_base *obj)
添加对象到退役列表
void clear()
清空并销毁所有对象
hazard_pointer_obj_base * head
链表头
retire_list & operator=(retire_list &&other) noexcept
移动赋值运算符
~retire_list()
析构函数
动态大小数组容器