This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
[saferecl.hp.base]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.base)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#base)
#### 32.11.3.3 Class template hazard_pointer_obj_base [saferecl.hp.base]
namespace std {template<class T, class D = default_delete<T>>class hazard_pointer_obj_base {public:void retire(D d = D()) noexcept; protected: hazard_pointer_obj_base() = default;
hazard_pointer_obj_base(const hazard_pointer_obj_base&) = default;
hazard_pointer_obj_base(hazard_pointer_obj_base&&) = default;
hazard_pointer_obj_base& operator=(const hazard_pointer_obj_base&) = default;
hazard_pointer_obj_base& operator=(hazard_pointer_obj_base&&) = default; ~hazard_pointer_obj_base() = default; private: D *deleter*; // *exposition only*};}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13420)
D shall be a function object type ([[func.require]](func.require "22.10.4Requirements"))
for which, given a value d of type D and
a value ptr of type T*,
the expression d(ptr) is valid[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13426)
The behavior of a program
that adds specializations for hazard_pointer_obj_base is undefined[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13430)
D shall meet the requirements for[*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and [*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]")[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13434)
T may be an incomplete type[.](#4.sentence-1)
It shall be complete before any member
of the resulting specialization of hazard_pointer_obj_base is referenced[.](#4.sentence-2)
[🔗](#lib:retire,hazard_pointer_obj_base)
`void retire(D d = D()) noexcept;
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13446)
*Mandates*: T is a hazard-protectable type[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13450)
*Preconditions*: *this is
a base class subobject of an object x of type T[.](#6.sentence-1)
x is not retired[.](#6.sentence-2)
Move-assigning d to deleter does not exit via an exception[.](#6.sentence-3)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13457)
*Effects*: Move-assigns d to deleter,
thereby setting it as the deleter of x,
then retires x[.](#7.sentence-1)
May reclaim possibly-reclaimable objects[.](#7.sentence-2)

View File

@@ -0,0 +1,127 @@
[saferecl.hp.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.general)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#general)
#### 32.11.3.1 General [saferecl.hp.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13272)
A hazard pointer is a single-writer multi-reader pointer
that can be owned by at most one thread at any time[.](#1.sentence-1)
Only the owner of the hazard pointer can set its value,
while any number of threads may read its value[.](#1.sentence-2)
The owner thread sets the value of a hazard pointer to point to an object
in order to indicate to concurrent threads—which
may delete such an object—that
the object is not yet safe to delete[.](#1.sentence-3)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13283)
A class type T is [*hazard-protectable*](#def:hazard-protectable "32.11.3.1General[saferecl.hp.general]") if it has exactly one base class of type hazard_pointer_obj_base<T, D> for some D,
that base is public and non-virtual, and
it has no base classes of type hazard_pointer_obj_base<T2, D2> for any other combination T2, D2[.](#2.sentence-1)
An object is [*hazard-protectable*](#def:hazard-protectable "32.11.3.1General[saferecl.hp.general]") if it is of hazard-protectable type[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13292)
The time span between creation and destruction of a hazard pointer h is partitioned into a series of [*protection epochs*](#def:epoch,protection "32.11.3.1General[saferecl.hp.general]");
in each protection epoch,h either is [*associated with*](#def:hazard_pointer,associated "32.11.3.1General[saferecl.hp.general]") a hazard-protectable object, or is [*unassociated*](#def:hazard_pointer,unassociated "32.11.3.1General[saferecl.hp.general]")[.](#3.sentence-1)
Upon creation, a hazard pointer is unassociated[.](#3.sentence-2)
Changing the association (possibly to the same object)
initiates a new protection epoch and ends the preceding one[.](#3.sentence-3)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13302)
An object x of hazard-protectable type T is[*retired*](#def:retired "32.11.3.1General[saferecl.hp.general]") with a deleter of type D when the member function hazard_pointer_obj_base<T, D>::retire is invoked on x[.](#4.sentence-1)
Any given object x shall be retired at most once[.](#4.sentence-2)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13309)
A retired object x is [*reclaimed*](#def:reclaimed "32.11.3.1General[saferecl.hp.general]") by invoking its deleter with a pointer to x;
the behavior is undefined if that invocation exits via an exception[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13314)
A hazard-protectable object x is [*possibly-reclaimable*](#def:possibly-reclaimable "32.11.3.1General[saferecl.hp.general]") with respect to an evaluation A if
- [(6.1)](#6.1)
x is not reclaimed; and
- [(6.2)](#6.2)
x is retired in an evaluation R andA does not happen before R; and
- [(6.3)](#6.3)
for all hazard pointers h and for every protection epoch E of h during which h is associated with x:
* [(6.3.1)](#6.3.1)
if the beginning of E happens before R,
the end of E strongly happens before A; and
* [(6.3.2)](#6.3.2)
if E began by an evaluation of try_protect with argument src,
label its atomic load operation L[.](#6.sentence-1)
If there exists an atomic modification B on src such that L observes a modification that is modification-ordered before B, andB happens before x is retired,
the end of E strongly happens before A[.](#6.3.2.sentence-2)
[*Note [1](#note-1)*:
In typical use, a store to src sequenced before retiring x will be such an atomic operation B[.](#6.3.2.sentence-3)
— *end note*]
[*Note [2](#note-2)*:
The latter two conditions convey the informal notion
that a protection epoch that began before retiring x,
as implied either by the happens-before relation or
the coherence order of some source,
delays the reclamation of x[.](#6.3.sentence-2)
— *end note*]
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13351)
The number of possibly-reclaimable objects has an unspecified bound[.](#7.sentence-1)
[*Note [3](#note-3)*:
The bound can be a function of the number of hazard pointers,
the number of threads that retire objects, and
the number of threads that use hazard pointers[.](#7.sentence-2)
— *end note*]
[*Example [1](#example-1)*:
The following example shows how hazard pointers allow updates to be carried out
in the presence of concurrent readers[.](#7.sentence-3)
The object of type hazard_pointer in print_name protects the object *ptr from being reclaimed by ptr->retire until the end of the protection epoch[.](#7.sentence-4)
struct Name : public hazard_pointer_obj_base<Name> { /* details */ };
atomic<Name*> name;// called often and in parallel!void print_name() { hazard_pointer h = make_hazard_pointer();
Name* ptr = h.protect(name); // Protection epoch starts// ... safe to access *ptr} // Protection epoch ends.// called rarely, but possibly concurrently with print_namevoid update_name(Name* new_name) { Name* ptr = name.exchange(new_name);
ptr->retire();} — *end example*]

View File

@@ -0,0 +1,294 @@
[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)

View File

@@ -0,0 +1,80 @@
[saferecl.hp.holder.ctor]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder.ctor)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder.ctor)
#### 32.11.3.4 Class hazard_pointer [[saferecl.hp.holder]](saferecl.hp.holder#ctor)
#### 32.11.3.4.2 Constructors, destructor, and assignment [saferecl.hp.holder.ctor]
[🔗](#lib:hazard_pointer,constructor)
`hazard_pointer() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13508)
*Postconditions*: *this is empty[.](#1.sentence-1)
[🔗](#lib:hazard_pointer,constructor_)
`hazard_pointer(hazard_pointer&& other) noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13519)
*Postconditions*: If other is empty, *this is empty[.](#2.sentence-1)
Otherwise,*this owns the hazard pointer originally owned by other;other is empty[.](#2.sentence-2)
[🔗](#lib:hazard_pointer,destructor)
`~hazard_pointer();
`
[3](#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[.](#3.sentence-1)
[🔗](#lib:operator=,hazard_pointer)
`hazard_pointer& operator=(hazard_pointer&& other) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13546)
*Effects*: If this == &other is true, no effect[.](#4.sentence-1)
Otherwise, if *this is not empty,
destroys the hazard pointer owned by *this,
thereby ending its current protection epoch[.](#4.sentence-2)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13553)
*Postconditions*: If other was empty, *this is empty[.](#5.sentence-1)
Otherwise, *this owns the hazard pointer originally
owned by other[.](#5.sentence-2)
If this != &other is true, other is empty[.](#5.sentence-3)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13560)
*Returns*: *this[.](#6.sentence-1)

View File

@@ -0,0 +1,34 @@
[saferecl.hp.holder.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder.general)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder.general)
#### 32.11.3.4 Class hazard_pointer [[saferecl.hp.holder]](saferecl.hp.holder#general)
#### 32.11.3.4.1 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](#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[.](#1.sentence-1)
Each hazard pointer is owned by
exactly one object of type hazard_pointer[.](#1.sentence-2)
[*Note [1](#note-1)*:
An empty hazard_pointer object is different from
a hazard_pointer object
that owns an unassociated hazard pointer[.](#1.sentence-3)
An empty hazard_pointer object does not own any hazard pointers[.](#1.sentence-4)
— *end note*]

View File

@@ -0,0 +1,162 @@
[saferecl.hp.holder.mem]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder.mem)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder.mem)
#### 32.11.3.4 Class hazard_pointer [[saferecl.hp.holder]](saferecl.hp.holder#mem)
#### 32.11.3.4.3 Member functions [saferecl.hp.holder.mem]
[🔗](#lib:empty,hazard_pointer)
`bool empty() const noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13573)
*Returns*: true if and only if *this is empty[.](#1.sentence-1)
[🔗](#lib:protect,hazard_pointer)
`template<class T> T* protect(const atomic<T*>& src) noexcept;
`
[2](#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](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13600)
*Mandates*: T is a hazard-protectable type[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13604)
*Preconditions*: *this is not empty[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13608)
*Effects*: Performs the following steps in order:
- [(5.1)](#5.1)
Initializes a variable old of type T* with the value of ptr[.](#5.1.sentence-1)
- [(5.2)](#5.2)
Evaluates reset_protection(old)[.](#5.2.sentence-1)
- [(5.3)](#5.3)
Assigns the value of src.load(memory_order::acquire) to ptr[.](#5.3.sentence-1)
- [(5.4)](#5.4)
If old == ptr is false,
evaluates reset_protection()[.](#5.4.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13619)
*Returns*: old == ptr[.](#6.sentence-1)
[🔗](#lib:reset_protection,hazard_pointer)
`template<class T> void reset_protection(const T* ptr) noexcept;
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13630)
*Mandates*: T is a hazard-protectable type[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13634)
*Preconditions*: *this is not empty[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13638)
*Effects*: If ptr is a null pointer value, invokes reset_protection()[.](#9.sentence-1)
Otherwise,
associates the hazard pointer owned by *this with *ptr,
thereby ending the current protection epoch[.](#9.sentence-2)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13645)
*Complexity*: Constant[.](#10.sentence-1)
[🔗](#lib:reset_protection,hazard_pointer_)
`void reset_protection(nullptr_t = nullptr) noexcept;
`
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13656)
*Preconditions*: *this is not empty[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13660)
*Postconditions*: The hazard pointer owned by *this is unassociated[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13664)
*Complexity*: Constant[.](#13.sentence-1)
[🔗](#lib:swap,hazard_pointer)
`void swap(hazard_pointer& other) noexcept;
`
[14](#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[.](#14.sentence-1)
[*Note [1](#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[.](#14.sentence-2)
No protection epochs are ended or initiated[.](#14.sentence-3)
— *end note*]
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13685)
*Complexity*: Constant[.](#15.sentence-1)

View File

@@ -0,0 +1,45 @@
[saferecl.hp.holder.nonmem]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#hp.holder.nonmem)
### 32.11.3 Hazard pointers [[saferecl.hp]](saferecl.hp#holder.nonmem)
#### 32.11.3.4 Class hazard_pointer [[saferecl.hp.holder]](saferecl.hp.holder#nonmem)
#### 32.11.3.4.4 Non-member functions [saferecl.hp.holder.nonmem]
[🔗](#lib:make_hazard_pointer)
`hazard_pointer make_hazard_pointer();
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13698)
*Effects*: Constructs a hazard pointer[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13702)
*Returns*: A hazard_pointer object that owns the newly-constructed hazard pointer[.](#2.sentence-1)
[3](#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[.](#3.sentence-1)
[🔗](#lib:swap,hazard_pointer)
`void swap(hazard_pointer& a, hazard_pointer& b) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13718)
*Effects*: Equivalent to a.swap(b)[.](#4.sentence-1)