Files
2025-10-25 03:02:53 +03:00

295 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[saferecl.hp.holder]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder)
#### 32.11.3.4 Class hazard_pointer [saferecl.hp.holder]
#### [32.11.3.4.1](#general) General [[saferecl.hp.holder.general]](saferecl.hp.holder.general)
namespace std {class hazard_pointer {public: hazard_pointer() noexcept;
hazard_pointer(hazard_pointer&&) noexcept;
hazard_pointer& operator=(hazard_pointer&&) noexcept; ~hazard_pointer(); bool empty() const noexcept; template<class T> T* protect(const atomic<T*>& src) noexcept; template<class T> bool try_protect(T*& ptr, const atomic<T*>& src) noexcept; template<class T> void reset_protection(const T* ptr) noexcept; void reset_protection(nullptr_t = nullptr) noexcept; void swap(hazard_pointer&) noexcept; };}
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13488)
An object of type hazard_pointer is either empty or[*owns*](#def:owning,hazard_pointer "32.11.3.4.1General[saferecl.hp.holder.general]") a hazard pointer[.](#general-1.sentence-1)
Each hazard pointer is owned by
exactly one object of type hazard_pointer[.](#general-1.sentence-2)
[*Note [1](#general-note-1)*:
An empty hazard_pointer object is different from
a hazard_pointer object
that owns an unassociated hazard pointer[.](#general-1.sentence-3)
An empty hazard_pointer object does not own any hazard pointers[.](#general-1.sentence-4)
— *end note*]
#### [32.11.3.4.2](#ctor) Constructors, destructor, and assignment [[saferecl.hp.holder.ctor]](saferecl.hp.holder.ctor)
[🔗](#lib:hazard_pointer,constructor)
`hazard_pointer() noexcept;
`
[1](#ctor-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13508)
*Postconditions*: *this is empty[.](#ctor-1.sentence-1)
[🔗](#lib:hazard_pointer,constructor_)
`hazard_pointer(hazard_pointer&& other) noexcept;
`
[2](#ctor-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13519)
*Postconditions*: If other is empty, *this is empty[.](#ctor-2.sentence-1)
Otherwise,*this owns the hazard pointer originally owned by other;other is empty[.](#ctor-2.sentence-2)
[🔗](#lib:hazard_pointer,destructor)
`~hazard_pointer();
`
[3](#ctor-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13533)
*Effects*: If *this is not empty,
destroys the hazard pointer owned by *this,
thereby ending its current protection epoch[.](#ctor-3.sentence-1)
[🔗](#lib:operator=,hazard_pointer)
`hazard_pointer& operator=(hazard_pointer&& other) noexcept;
`
[4](#ctor-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13546)
*Effects*: If this == &other is true, no effect[.](#ctor-4.sentence-1)
Otherwise, if *this is not empty,
destroys the hazard pointer owned by *this,
thereby ending its current protection epoch[.](#ctor-4.sentence-2)
[5](#ctor-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13553)
*Postconditions*: If other was empty, *this is empty[.](#ctor-5.sentence-1)
Otherwise, *this owns the hazard pointer originally
owned by other[.](#ctor-5.sentence-2)
If this != &other is true, other is empty[.](#ctor-5.sentence-3)
[6](#ctor-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13560)
*Returns*: *this[.](#ctor-6.sentence-1)
#### [32.11.3.4.3](#mem) Member functions [[saferecl.hp.holder.mem]](saferecl.hp.holder.mem)
[🔗](#lib:empty,hazard_pointer)
`bool empty() const noexcept;
`
[1](#mem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13573)
*Returns*: true if and only if *this is empty[.](#mem-1.sentence-1)
[🔗](#lib:protect,hazard_pointer)
`template<class T> T* protect(const atomic<T*>& src) noexcept;
`
[2](#mem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13584)
*Effects*: Equivalent to:T* ptr = src.load(memory_order::relaxed);while (!try_protect(ptr, src)) {}return ptr;
[🔗](#lib:try_protect,hazard_pointer)
`template<class T> bool try_protect(T*& ptr, const atomic<T*>& src) noexcept;
`
[3](#mem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13600)
*Mandates*: T is a hazard-protectable type[.](#mem-3.sentence-1)
[4](#mem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13604)
*Preconditions*: *this is not empty[.](#mem-4.sentence-1)
[5](#mem-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13608)
*Effects*: Performs the following steps in order:
- [(5.1)](#mem-5.1)
Initializes a variable old of type T* with the value of ptr[.](#mem-5.1.sentence-1)
- [(5.2)](#mem-5.2)
Evaluates reset_protection(old)[.](#mem-5.2.sentence-1)
- [(5.3)](#mem-5.3)
Assigns the value of src.load(memory_order::acquire) to ptr[.](#mem-5.3.sentence-1)
- [(5.4)](#mem-5.4)
If old == ptr is false,
evaluates reset_protection()[.](#mem-5.4.sentence-1)
[6](#mem-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13619)
*Returns*: old == ptr[.](#mem-6.sentence-1)
[🔗](#lib:reset_protection,hazard_pointer)
`template<class T> void reset_protection(const T* ptr) noexcept;
`
[7](#mem-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13630)
*Mandates*: T is a hazard-protectable type[.](#mem-7.sentence-1)
[8](#mem-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13634)
*Preconditions*: *this is not empty[.](#mem-8.sentence-1)
[9](#mem-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13638)
*Effects*: If ptr is a null pointer value, invokes reset_protection()[.](#mem-9.sentence-1)
Otherwise,
associates the hazard pointer owned by *this with *ptr,
thereby ending the current protection epoch[.](#mem-9.sentence-2)
[10](#mem-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13645)
*Complexity*: Constant[.](#mem-10.sentence-1)
[🔗](#lib:reset_protection,hazard_pointer_)
`void reset_protection(nullptr_t = nullptr) noexcept;
`
[11](#mem-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13656)
*Preconditions*: *this is not empty[.](#mem-11.sentence-1)
[12](#mem-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13660)
*Postconditions*: The hazard pointer owned by *this is unassociated[.](#mem-12.sentence-1)
[13](#mem-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13664)
*Complexity*: Constant[.](#mem-13.sentence-1)
[🔗](#lib:swap,hazard_pointer)
`void swap(hazard_pointer& other) noexcept;
`
[14](#mem-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13675)
*Effects*: Swaps the hazard pointer ownership of this object with that of other[.](#mem-14.sentence-1)
[*Note [1](#mem-note-1)*:
The owned hazard pointers, if any, remain unchanged during the swap and
continue to be associated with the respective objects
that they were protecting before the swap, if any[.](#mem-14.sentence-2)
No protection epochs are ended or initiated[.](#mem-14.sentence-3)
— *end note*]
[15](#mem-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13685)
*Complexity*: Constant[.](#mem-15.sentence-1)
#### [32.11.3.4.4](#nonmem) Non-member functions [[saferecl.hp.holder.nonmem]](saferecl.hp.holder.nonmem)
[🔗](#lib:make_hazard_pointer)
`hazard_pointer make_hazard_pointer();
`
[1](#nonmem-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13698)
*Effects*: Constructs a hazard pointer[.](#nonmem-1.sentence-1)
[2](#nonmem-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13702)
*Returns*: A hazard_pointer object that owns the newly-constructed hazard pointer[.](#nonmem-2.sentence-1)
[3](#nonmem-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13706)
*Throws*: May throw bad_alloc if memory for the hazard pointer could not be allocated[.](#nonmem-3.sentence-1)
[🔗](#lib:swap,hazard_pointer_)
`void swap(hazard_pointer& a, hazard_pointer& b) noexcept;
`
[4](#nonmem-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13718)
*Effects*: Equivalent to a.swap(b)[.](#nonmem-4.sentence-1)