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

128 lines
5.6 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.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*]