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 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};
91
100template <typename T, typename Deleter = default_delete<void>>
102 T* ptr;
103 Deleter deleter;
104
105public:
111 explicit hazard_pointer_obj(T* p, Deleter d = Deleter()) :
112 ptr(p),
113 deleter(_NEFORCE move(d)) {}
114
118 void destroy() override { deleter(ptr); }
119};
120
129 size_t count{0};
130
136 obj->next = head;
137 head = obj;
138 ++count;
139 }
140
144 void clear() {
145 while (head) {
146 auto* next = head->next;
147 head->destroy();
148 delete head;
149 head = next;
150 }
151 count = 0;
152 }
153
158};
159
166class hazard_pointer_domain {
167private:
168 atomic<hazard_pointer_record*> head_{nullptr};
169
170 static thread_local retire_list tl_retire_list_;
171
172 static constexpr size_t RETIRE_THRESHOLD = 100;
173
178 vector<void*> get_hazard_pointers() {
179 vector<void*> hazards;
180 hazard_pointer_record* current = head_.load(memory_order_acquire);
181
182 while (current) {
183 if (current->active.load(memory_order_acquire)) {
184 void* ptr = current->get_protected();
185 if (ptr) {
186 hazards.push_back(ptr);
187 }
188 }
189 current = current->next.load(memory_order_acquire);
190 }
191
192 return hazards;
193 }
194
201 void scan_and_reclaim() {
202 auto hazards = get_hazard_pointers();
203 _NEFORCE sort(hazards.begin(), hazards.end());
204
205 retire_list new_list;
206 hazard_pointer_obj_base* current = tl_retire_list_.head;
207
208 while (current) {
209 auto* next = current->next;
210
211 if (_NEFORCE binary_search(hazards.begin(), hazards.end(), current)) {
212 new_list.add(current);
213 } else {
214 current->destroy();
215 delete current;
216 }
217
218 current = next;
219 }
220
221 tl_retire_list_ = _NEFORCE move(new_list);
222 }
223
224public:
225 hazard_pointer_domain() = default;
226
233 hazard_pointer_record* current = head_.load();
234 while (current) {
235 auto* next = current->next.load();
236 delete current;
237 current = next;
238 }
239 }
240
242 hazard_pointer_domain& operator=(const hazard_pointer_domain&) = delete;
243
251 hazard_pointer_record* current = head_.load(memory_order_acquire);
252 while (current) {
253 if (current->try_acquire()) {
254 return current;
255 }
256 current = current->next.load(memory_order_acquire);
257 }
258
260 new_record->active.store(true, memory_order_relaxed);
261
262 hazard_pointer_record* old_head = head_.load(memory_order_relaxed);
263 do {
264 new_record->next.store(old_head, memory_order_relaxed);
265 } while (!head_.compare_exchange_weak(old_head, new_record, memory_order_release, memory_order_relaxed));
266
267 return new_record;
268 }
269
279 template <typename T, typename Deleter = default_delete<T>>
280 void retire(T* ptr, Deleter deleter = Deleter()) {
281 if (!ptr) {
282 return;
283 }
284
285 auto* obj = new hazard_pointer_obj<T, Deleter>(ptr, _NEFORCE move(deleter));
286 tl_retire_list_.add(obj);
287
288 if (tl_retire_list_.count >= RETIRE_THRESHOLD) {
289 scan_and_reclaim();
290 }
291 }
292
296 void reclaim() { scan_and_reclaim(); }
297
302 static hazard_pointer_domain& default_domain() {
303 static hazard_pointer_domain domain{};
304 return domain;
305 }
306};
307
308
315class hazard_pointer {
316private:
317 hazard_pointer_record* record_{nullptr};
318 hazard_pointer_domain* domain_{nullptr};
319
320public:
321 hazard_pointer() = default;
322
330 domain_(&domain) {
331 record_ = domain_->acquire_record();
332 }
333
341 if (record_) {
342 record_->release();
343 }
344 }
345
346 hazard_pointer(hazard_pointer&& other) noexcept :
347 record_(other.record_),
348 domain_(other.domain_) {
349 other.record_ = nullptr;
350 other.domain_ = nullptr;
351 }
352
353 hazard_pointer& operator=(hazard_pointer&& other) noexcept {
354 if (addressof(other) == this) {
355 return *this;
356 }
357
359 if (record_) {
360 record_->release();
361 }
362 record_ = other.record_;
363 domain_ = other.domain_;
364 other.record_ = nullptr;
365 other.domain_ = nullptr;
366
367 return *this;
368 }
369
370 hazard_pointer(const hazard_pointer&) = delete;
371 hazard_pointer& operator=(const hazard_pointer&) = delete;
372
381 template <typename T>
382 T* protect(const atomic<T*>& src) {
383 if (!record_) {
384 return nullptr;
385 }
386
387 T* ptr = src.load(memory_order_relaxed);
388 while (true) {
389 record_->protect(ptr);
390 T* ptr2 = src.load(memory_order_acquire);
391 if (ptr == ptr2) {
392 return ptr;
393 }
394 ptr = ptr2;
395 }
396 }
397
405 template <typename T>
406 bool try_protect(T*& ptr, const atomic<T*>& src) {
407 if (!record_) {
408 return false;
409 }
410
411 ptr = src.load(memory_order_relaxed);
412 record_->protect(ptr);
413 T* ptr2 = src.load(memory_order_acquire);
414
415 if (ptr == ptr2) {
416 return true;
417 }
418
419 ptr = ptr2;
420 return false;
421 }
422
428 void reset_protection() noexcept {
429 if (record_) {
430 record_->protect(nullptr);
431 }
432 }
433
438 void swap(hazard_pointer& other) noexcept {
439 _NEFORCE swap(record_, other.record_);
440 _NEFORCE swap(domain_, other.domain_);
441 }
442
447 explicit operator bool() const noexcept { return record_ != nullptr; }
448};
449
458
459
467template <typename T>
468class hazard_pointer_holder {
469private:
470 hazard_pointer hp_;
471 T* ptr_{nullptr};
472
473public:
474 hazard_pointer_holder() = default;
475
481 hp_(domain) {}
482
488 T* protect(const atomic<T*>& src) {
489 ptr_ = hp_.protect(src);
490 return ptr_;
491 }
492
497 T* get() const noexcept { return ptr_; }
498
503 T& operator*() const noexcept { return *ptr_; }
504
509 T* operator->() const noexcept { return ptr_; }
510
515 explicit operator bool() const noexcept { return ptr_ != nullptr; }
516
520 void reset() noexcept {
521 hp_.reset_protection();
522 ptr_ = nullptr;
523 }
524};
525 // HazardPointer
527 // AsyncComponents
529
530NEFORCE_END_NAMESPACE__
531#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 destroy()=0
销毁对象
hazard_pointer_obj_base * next
链表中的下一个对象
险象指针对象模板
hazard_pointer_obj(T *p, Deleter d=Deleter())
构造函数
void destroy() 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)
构造函数
动态大小数组容器
NEFORCE_CONSTEXPR20 void push_back(const T &value)
在末尾拷贝插入元素
智能指针删除器
NEFORCE_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr bool binary_search(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)
获取迭代器的后一个位置
NEFORCE_INLINE17 constexpr auto memory_order_release
释放内存顺序常量
NEFORCE_INLINE17 constexpr auto memory_order_relaxed
宽松内存顺序常量
NEFORCE_INLINE17 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重载
排序算法
void store(const bool value, const memory_order mo=memory_order_seq_cst) noexcept
原子存储操作
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 store(T value, const memory_order mo=memory_order_seq_cst) 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()
析构函数
动态大小数组容器