295 lines
9.0 KiB
Markdown
295 lines
9.0 KiB
Markdown
[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.1 General [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)
|