From Jason Turner

[saferecl]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmprxqww1oj/{from.md → to.md} +809 -0
tmp/tmprxqww1oj/{from.md → to.md} RENAMED
@@ -0,0 +1,809 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Safe reclamation <a id="saferecl">[[saferecl]]</a>
2
+
3
+ ### General <a id="saferecl.general">[[saferecl.general]]</a>
4
+
5
+ Subclause [[saferecl]] contains safe-reclamation techniques, which are
6
+ most frequently used to straightforwardly resolve access-deletion races.
7
+
8
+ ### Read-copy update (RCU) <a id="saferecl.rcu">[[saferecl.rcu]]</a>
9
+
10
+ #### General <a id="saferecl.rcu.general">[[saferecl.rcu.general]]</a>
11
+
12
+ RCU is a synchronization mechanism that can be used for linked data
13
+ structures that are frequently read, but seldom updated. RCU does not
14
+ provide mutual exclusion, but instead allows the user to schedule
15
+ specified actions such as deletion at some later time.
16
+
17
+ A class type `T` is *rcu-protectable* if it has exactly one base class
18
+ of type `rcu_obj_base<T, D>` for some `D`, and that base is public and
19
+ non-virtual, and it has no base classes of type `rcu_obj_base<X, Y>` for
20
+ any other combination `X`, `Y`. An object is rcu-protectable if it is of
21
+ rcu-protectable type.
22
+
23
+ An invocation of `unlock` U on an `rcu_domain dom` corresponds to an
24
+ invocation of `lock` L on `dom` if L is sequenced before U and either
25
+
26
+ - no other invocation of `lock` on `dom` is sequenced after L and before
27
+ U, or
28
+ - every invocation of `unlock` U2 on `dom` such that L is sequenced
29
+ before U2 and U2 is sequenced before U corresponds to an invocation of
30
+ `lock` L2 on `dom` such that L is sequenced before L2 and L2 is
31
+ sequenced before U2.
32
+
33
+ [*Note 1*: This pairs nested locks and unlocks on a given domain in
34
+ each thread. — *end note*]
35
+
36
+ A *region of RCU protection* on a domain `dom` starts with a `lock` L on
37
+ `dom` and ends with its corresponding `unlock` U.
38
+
39
+ Given a region of RCU protection R on a domain `dom` and given an
40
+ evaluation E that scheduled another evaluation F in `dom`, if E does not
41
+ strongly happen before the start of R, the end of R strongly happens
42
+ before evaluating F.
43
+
44
+ The evaluation of a scheduled evaluation is potentially concurrent with
45
+ any other scheduled evaluation. Each scheduled evaluation is evaluated
46
+ at most once.
47
+
48
+ #### Header `<rcu>` synopsis <a id="rcu.syn">[[rcu.syn]]</a>
49
+
50
+ ``` cpp
51
+ namespace std {
52
+ // [saferecl.rcu.base], class template rcu_obj_base
53
+ template<class T, class D = default_delete<T>> class rcu_obj_base;
54
+
55
+ // [saferecl.rcu.domain], class rcu_domain
56
+ class rcu_domain;
57
+
58
+ // [saferecl.rcu.domain.func], non-member functions
59
+ rcu_domain& rcu_default_domain() noexcept;
60
+ void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
61
+ void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
62
+ template<class T, class D = default_delete<T>>
63
+ void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
64
+ }
65
+ ```
66
+
67
+ #### Class template `rcu_obj_base` <a id="saferecl.rcu.base">[[saferecl.rcu.base]]</a>
68
+
69
+ Objects of type `T` to be protected by RCU inherit from a specialization
70
+ `rcu_obj_base<T, D>` for some `D`.
71
+
72
+ ``` cpp
73
+ namespace std {
74
+ template<class T, class D = default_delete<T>>
75
+ class rcu_obj_base {
76
+ public:
77
+ void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
78
+ protected:
79
+ rcu_obj_base() = default;
80
+ rcu_obj_base(const rcu_obj_base&) = default;
81
+ rcu_obj_base(rcu_obj_base&&) = default;
82
+ rcu_obj_base& operator=(const rcu_obj_base&) = default;
83
+ rcu_obj_base& operator=(rcu_obj_base&&) = default;
84
+ ~rcu_obj_base() = default;
85
+ private:
86
+ D deleter; // exposition only
87
+ };
88
+ }
89
+ ```
90
+
91
+ The behavior of a program that adds specializations for `rcu_obj_base`
92
+ is undefined.
93
+
94
+ `T` may be an incomplete type. It shall be complete before any member of
95
+ the resulting specialization of `rcu_obj_base` is referenced.
96
+
97
+ `D` shall be a function object type [[function.objects]] for which,
98
+ given a value `d` of type `D` and a value `ptr` of type `T*`, the
99
+ expression `d(ptr)` is valid.
100
+
101
+ `D` shall meet the requirements for *Cpp17DefaultConstructible* and
102
+ *Cpp17MoveAssignable*.
103
+
104
+ If `D` is trivially copyable, all specializations of
105
+ `rcu_obj_base<T, D>` are trivially copyable.
106
+
107
+ ``` cpp
108
+ void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
109
+ ```
110
+
111
+ *Mandates:* `T` is an rcu-protectable type.
112
+
113
+ *Preconditions:* `*this` is a base class subobject of an object `x` of
114
+ type `T`. The member function `rcu_obj_base<T, D>::retire` was not
115
+ invoked on `x` before. The assignment to *deleter* does not exit via an
116
+ exception.
117
+
118
+ *Effects:* Evaluates *`deleter`*` = std::move(d)` and schedules the
119
+ evaluation of the expression *`deleter`*`( addressof(x))` in the domain
120
+ `dom`; the behavior is undefined if that evaluation exits via an
121
+ exception. May invoke scheduled evaluations in `dom`.
122
+
123
+ [*Note 1*: If such evaluations acquire resources held across any
124
+ invocation of `retire` on `dom`, deadlock can occur. — *end note*]
125
+
126
+ #### Class `rcu_domain` <a id="saferecl.rcu.domain">[[saferecl.rcu.domain]]</a>
127
+
128
+ ##### General <a id="saferecl.rcu.domain.general">[[saferecl.rcu.domain.general]]</a>
129
+
130
+ ``` cpp
131
+ namespace std {
132
+ class rcu_domain {
133
+ public:
134
+ rcu_domain(const rcu_domain&) = delete;
135
+ rcu_domain& operator=(const rcu_domain&) = delete;
136
+
137
+ void lock() noexcept;
138
+ bool try_lock() noexcept;
139
+ void unlock() noexcept;
140
+ };
141
+ }
142
+ ```
143
+
144
+ This class meets the requirements of *Cpp17Lockable*
145
+ [[thread.req.lockable.req]] and provides regions of RCU protection.
146
+
147
+ [*Example 1*:
148
+
149
+ ``` cpp
150
+ std::scoped_lock<rcu_domain> rlock(rcu_default_domain());
151
+ ```
152
+
153
+ — *end example*]
154
+
155
+ The functions `lock` and `unlock` establish (possibly nested) regions of
156
+ RCU protection.
157
+
158
+ ##### Member functions <a id="saferecl.rcu.domain.members">[[saferecl.rcu.domain.members]]</a>
159
+
160
+ ``` cpp
161
+ void lock() noexcept;
162
+ ```
163
+
164
+ *Effects:* Opens a region of RCU protection.
165
+
166
+ *Remarks:* Calls to `lock` do not introduce a data race [[intro.races]]
167
+ involving `*this`.
168
+
169
+ ``` cpp
170
+ bool try_lock() noexcept;
171
+ ```
172
+
173
+ *Effects:* Equivalent to `lock()`.
174
+
175
+ *Returns:* `true`.
176
+
177
+ ``` cpp
178
+ void unlock() noexcept;
179
+ ```
180
+
181
+ *Preconditions:* A call to `lock` that opened an unclosed region of RCU
182
+ protection is sequenced before the call to `unlock`.
183
+
184
+ *Effects:* Closes the unclosed region of RCU protection that was most
185
+ recently opened. May invoke scheduled evaluations in `*this`.
186
+
187
+ [*Note 1*: If such evaluations acquire resources held across any
188
+ invocation of `unlock` on `*this`, deadlock can occur. — *end note*]
189
+
190
+ *Remarks:* Calls to `unlock` do not introduce a data race involving
191
+ `*this`.
192
+
193
+ [*Note 2*: Evaluation of scheduled evaluations can still cause a data
194
+ race. — *end note*]
195
+
196
+ ##### Non-member functions <a id="saferecl.rcu.domain.func">[[saferecl.rcu.domain.func]]</a>
197
+
198
+ ``` cpp
199
+ rcu_domain& rcu_default_domain() noexcept;
200
+ ```
201
+
202
+ *Returns:* A reference to a static-duration object of type `rcu_domain`.
203
+ A reference to the same object is returned every time this function is
204
+ called.
205
+
206
+ ``` cpp
207
+ void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
208
+ ```
209
+
210
+ *Effects:* If the call to `rcu_synchronize` does not strongly happen
211
+ before the lock opening an RCU protection region `R` on `dom`, blocks
212
+ until the `unlock` closing `R` happens.
213
+
214
+ *Synchronization:* The `unlock` closing `R` strongly happens before the
215
+ return from `rcu_synchronize`.
216
+
217
+ ``` cpp
218
+ void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
219
+ ```
220
+
221
+ *Effects:* May evaluate any scheduled evaluations in `dom`. For any
222
+ evaluation that happens before the call to `rcu_barrier` and that
223
+ schedules an evaluation E in `dom`, blocks until E has been evaluated.
224
+
225
+ *Synchronization:* The evaluation of any such E strongly happens before
226
+ the return from `rcu_barrier`.
227
+
228
+ [*Note 3*: A call to `rcu_barrier` does not imply a call to
229
+ `rcu_synchronize` and vice versa. — *end note*]
230
+
231
+ ``` cpp
232
+ template<class T, class D = default_delete<T>>
233
+ void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
234
+ ```
235
+
236
+ *Mandates:* `is_move_constructible_v<D>` is `true` and the expression
237
+ `d(p)` is well-formed.
238
+
239
+ *Preconditions:* `D` meets the *Cpp17MoveConstructible* and
240
+ *Cpp17Destructible* requirements.
241
+
242
+ *Effects:* May allocate memory. It is unspecified whether the memory
243
+ allocation is performed by invoking `operator new`. Initializes an
244
+ object `d1` of type `D` from `std::move(d)`. Schedules the evaluation of
245
+ `d1(p)` in the domain `dom`; the behavior is undefined if that
246
+ evaluation exits via an exception. May invoke scheduled evaluations in
247
+ `dom`.
248
+
249
+ [*Note 4*: If `rcu_retire` exits via an exception, no evaluation is
250
+ scheduled. — *end note*]
251
+
252
+ *Throws:* `bad_alloc` or any exception thrown by the initialization of
253
+ `d1`.
254
+
255
+ [*Note 5*: If scheduled evaluations acquire resources held across any
256
+ invocation of `rcu_retire` on `dom`, deadlock can occur. — *end note*]
257
+
258
+ ### Hazard pointers <a id="saferecl.hp">[[saferecl.hp]]</a>
259
+
260
+ #### General <a id="saferecl.hp.general">[[saferecl.hp.general]]</a>
261
+
262
+ A hazard pointer is a single-writer multi-reader pointer that can be
263
+ owned by at most one thread at any time. Only the owner of the hazard
264
+ pointer can set its value, while any number of threads may read its
265
+ value. The owner thread sets the value of a hazard pointer to point to
266
+ an object in order to indicate to concurrent threads—which may delete
267
+ such an object—that the object is not yet safe to delete.
268
+
269
+ A class type `T` is *hazard-protectable* if it has exactly one base
270
+ class of type `hazard_pointer_obj_base<T, D>` for some `D`, that base is
271
+ public and non-virtual, and it has no base classes of type
272
+ `hazard_pointer_obj_base<T2, D2>` for any other combination `T2`, `D2`.
273
+ An object is *hazard-protectable* if it is of hazard-protectable type.
274
+
275
+ The time span between creation and destruction of a hazard pointer h is
276
+ partitioned into a series of *protection epochs*; in each protection
277
+ epoch, h either is *associated with* a hazard-protectable object, or is
278
+ *unassociated*. Upon creation, a hazard pointer is unassociated.
279
+ Changing the association (possibly to the same object) initiates a new
280
+ protection epoch and ends the preceding one.
281
+
282
+ An object `x` of hazard-protectable type `T` is *retired* with a deleter
283
+ of type `D` when the member function
284
+ `hazard_pointer_obj_base<T, D>::retire` is invoked on `x`. Any given
285
+ object `x` shall be retired at most once.
286
+
287
+ A retired object `x` is *reclaimed* by invoking its deleter with a
288
+ pointer to `x`; the behavior is undefined if that invocation exits via
289
+ an exception.
290
+
291
+ A hazard-protectable object `x` is *possibly-reclaimable* with respect
292
+ to an evaluation A if
293
+
294
+ - `x` is not reclaimed; and
295
+ - `x` is retired in an evaluation R and A does not happen before R; and
296
+ - for all hazard pointers h and for every protection epoch E of h during
297
+ which h is associated with `x`:
298
+ - if the beginning of E happens before R, the end of E strongly
299
+ happens before A; and
300
+ - if E began by an evaluation of `try_protect` with argument `src`,
301
+ label its atomic load operation L. If there exists an atomic
302
+ modification B on `src` such that L observes a modification that is
303
+ modification-ordered before B, and B happens before `x` is retired,
304
+ the end of E strongly happens before A. \[*Note 1*: In typical use,
305
+ a store to `src` sequenced before retiring `x` will be such an
306
+ atomic operation B. — *end note*]
307
+
308
+ \[*Note 2*: The latter two conditions convey the informal notion that
309
+ a protection epoch that began before retiring `x`, as implied either
310
+ by the happens-before relation or the coherence order of some source,
311
+ delays the reclamation of `x`. — *end note*]
312
+
313
+ The number of possibly-reclaimable objects has an unspecified bound.
314
+
315
+ [*Note 3*: The bound can be a function of the number of hazard
316
+ pointers, the number of threads that retire objects, and the number of
317
+ threads that use hazard pointers. — *end note*]
318
+
319
+ [*Example 1*:
320
+
321
+ The following example shows how hazard pointers allow updates to be
322
+ carried out in the presence of concurrent readers. The object of type
323
+ `hazard_pointer` in `print_name` protects the object `*ptr` from being
324
+ reclaimed by `ptr->retire` until the end of the protection epoch.
325
+
326
+ ``` cpp
327
+ struct Name : public hazard_pointer_obj_base<Name> { /* details */ };
328
+ atomic<Name*> name;
329
+ // called often and in parallel!
330
+ void print_name() {
331
+ hazard_pointer h = make_hazard_pointer();
332
+ Name* ptr = h.protect(name); // Protection epoch starts
333
+ // ... safe to access *ptr
334
+ } // Protection epoch ends.
335
+
336
+ // called rarely, but possibly concurrently with print_name
337
+ void update_name(Name* new_name) {
338
+ Name* ptr = name.exchange(new_name);
339
+ ptr->retire();
340
+ }
341
+ ```
342
+
343
+ — *end example*]
344
+
345
+ #### Header `<hazard_pointer>` synopsis <a id="hazard.pointer.syn">[[hazard.pointer.syn]]</a>
346
+
347
+ ``` cpp
348
+ namespace std {
349
+ // [saferecl.hp.base], class template hazard_pointer_obj_base
350
+ template<class T, class D = default_delete<T>> class hazard_pointer_obj_base;
351
+
352
+ // [saferecl.hp.holder], class hazard_pointer
353
+ class hazard_pointer;
354
+
355
+ // [saferecl.hp.holder.nonmem], non-member functions
356
+ hazard_pointer make_hazard_pointer();
357
+ void swap(hazard_pointer&, hazard_pointer&) noexcept;
358
+ }
359
+ ```
360
+
361
+ #### Class template `hazard_pointer_obj_base` <a id="saferecl.hp.base">[[saferecl.hp.base]]</a>
362
+
363
+ ``` cpp
364
+ namespace std {
365
+ template<class T, class D = default_delete<T>>
366
+ class hazard_pointer_obj_base {
367
+ public:
368
+ void retire(D d = D()) noexcept;
369
+ protected:
370
+ hazard_pointer_obj_base() = default;
371
+ hazard_pointer_obj_base(const hazard_pointer_obj_base&) = default;
372
+ hazard_pointer_obj_base(hazard_pointer_obj_base&&) = default;
373
+ hazard_pointer_obj_base& operator=(const hazard_pointer_obj_base&) = default;
374
+ hazard_pointer_obj_base& operator=(hazard_pointer_obj_base&&) = default;
375
+ ~hazard_pointer_obj_base() = default;
376
+ private:
377
+ D deleter; // exposition only
378
+ };
379
+ }
380
+ ```
381
+
382
+ `D` shall be a function object type [[func.require]] for which, given a
383
+ value `d` of type `D` and a value `ptr` of type `T*`, the expression
384
+ `d(ptr)` is valid.
385
+
386
+ The behavior of a program that adds specializations for
387
+ `hazard_pointer_obj_base` is undefined.
388
+
389
+ `D` shall meet the requirements for *Cpp17DefaultConstructible* and
390
+ *Cpp17MoveAssignable*.
391
+
392
+ `T` may be an incomplete type. It shall be complete before any member of
393
+ the resulting specialization of `hazard_pointer_obj_base` is referenced.
394
+
395
+ ``` cpp
396
+ void retire(D d = D()) noexcept;
397
+ ```
398
+
399
+ *Mandates:* `T` is a hazard-protectable type.
400
+
401
+ *Preconditions:* `*this` is a base class subobject of an object `x` of
402
+ type `T`. `x` is not retired. Move-assigning `d` to `deleter` does not
403
+ exit via an exception.
404
+
405
+ *Effects:* Move-assigns `d` to `deleter`, thereby setting it as the
406
+ deleter of `x`, then retires `x`. May reclaim possibly-reclaimable
407
+ objects.
408
+
409
+ #### Class `hazard_pointer` <a id="saferecl.hp.holder">[[saferecl.hp.holder]]</a>
410
+
411
+ ##### General <a id="saferecl.hp.holder.general">[[saferecl.hp.holder.general]]</a>
412
+
413
+ ``` cpp
414
+ namespace std {
415
+ class hazard_pointer {
416
+ public:
417
+ hazard_pointer() noexcept;
418
+ hazard_pointer(hazard_pointer&&) noexcept;
419
+ hazard_pointer& operator=(hazard_pointer&&) noexcept;
420
+ ~hazard_pointer();
421
+
422
+ bool empty() const noexcept;
423
+ template<class T> T* protect(const atomic<T*>& src) noexcept;
424
+ template<class T> bool try_protect(T*& ptr, const atomic<T*>& src) noexcept;
425
+ template<class T> void reset_protection(const T* ptr) noexcept;
426
+ void reset_protection(nullptr_t = nullptr) noexcept;
427
+ void swap(hazard_pointer&) noexcept;
428
+ };
429
+ }
430
+ ```
431
+
432
+ An object of type `hazard_pointer` is either empty or *owns* a hazard
433
+ pointer. Each hazard pointer is owned by exactly one object of type
434
+ `hazard_pointer`.
435
+
436
+ [*Note 1*: An empty `hazard_pointer` object is different from a
437
+ `hazard_pointer` object that owns an unassociated hazard pointer. An
438
+ empty `hazard_pointer` object does not own any hazard
439
+ pointers. — *end note*]
440
+
441
+ ##### Constructors, destructor, and assignment <a id="saferecl.hp.holder.ctor">[[saferecl.hp.holder.ctor]]</a>
442
+
443
+ ``` cpp
444
+ hazard_pointer() noexcept;
445
+ ```
446
+
447
+ *Ensures:* `*this` is empty.
448
+
449
+ ``` cpp
450
+ hazard_pointer(hazard_pointer&& other) noexcept;
451
+ ```
452
+
453
+ *Ensures:* If `other` is empty, `*this` is empty. Otherwise, `*this`
454
+ owns the hazard pointer originally owned by `other`; `other` is empty.
455
+
456
+ ``` cpp
457
+ ~hazard_pointer();
458
+ ```
459
+
460
+ *Effects:* If `*this` is not empty, destroys the hazard pointer owned by
461
+ `*this`, thereby ending its current protection epoch.
462
+
463
+ ``` cpp
464
+ hazard_pointer& operator=(hazard_pointer&& other) noexcept;
465
+ ```
466
+
467
+ *Effects:* If `this == &other` is `true`, no effect. Otherwise, if
468
+ `*this` is not empty, destroys the hazard pointer owned by `*this`,
469
+ thereby ending its current protection epoch.
470
+
471
+ *Ensures:* If `other` was empty, `*this` is empty. Otherwise, `*this`
472
+ owns the hazard pointer originally owned by `other`. If `this != &other`
473
+ is `true`, `other` is empty.
474
+
475
+ *Returns:* `*this`.
476
+
477
+ ##### Member functions <a id="saferecl.hp.holder.mem">[[saferecl.hp.holder.mem]]</a>
478
+
479
+ ``` cpp
480
+ bool empty() const noexcept;
481
+ ```
482
+
483
+ *Returns:* `true` if and only if `*this` is empty.
484
+
485
+ ``` cpp
486
+ template<class T> T* protect(const atomic<T*>& src) noexcept;
487
+ ```
488
+
489
+ *Effects:* Equivalent to:
490
+
491
+ ``` cpp
492
+ T* ptr = src.load(memory_order::relaxed);
493
+ while (!try_protect(ptr, src)) {}
494
+ return ptr;
495
+ ```
496
+
497
+ ``` cpp
498
+ template<class T> bool try_protect(T*& ptr, const atomic<T*>& src) noexcept;
499
+ ```
500
+
501
+ *Mandates:* `T` is a hazard-protectable type.
502
+
503
+ *Preconditions:* `*this` is not empty.
504
+
505
+ *Effects:* Performs the following steps in order:
506
+
507
+ - Initializes a variable `old` of type `T*` with the value of `ptr`.
508
+ - Evaluates `reset_protection(old)`.
509
+ - Assigns the value of `src.load(memory_order::acquire)` to `ptr`.
510
+ - If `old == ptr` is `false`, evaluates `reset_protection()`.
511
+
512
+ *Returns:* `old == ptr`.
513
+
514
+ ``` cpp
515
+ template<class T> void reset_protection(const T* ptr) noexcept;
516
+ ```
517
+
518
+ *Mandates:* `T` is a hazard-protectable type.
519
+
520
+ *Preconditions:* `*this` is not empty.
521
+
522
+ *Effects:* If `ptr` is a null pointer value, invokes
523
+ `reset_protection()`. Otherwise, associates the hazard pointer owned by
524
+ `*this` with `*ptr`, thereby ending the current protection epoch.
525
+
526
+ *Complexity:* Constant.
527
+
528
+ ``` cpp
529
+ void reset_protection(nullptr_t = nullptr) noexcept;
530
+ ```
531
+
532
+ *Preconditions:* `*this` is not empty.
533
+
534
+ *Ensures:* The hazard pointer owned by `*this` is unassociated.
535
+
536
+ *Complexity:* Constant.
537
+
538
+ ``` cpp
539
+ void swap(hazard_pointer& other) noexcept;
540
+ ```
541
+
542
+ *Effects:* Swaps the hazard pointer ownership of this object with that
543
+ of `other`.
544
+
545
+ [*Note 1*: The owned hazard pointers, if any, remain unchanged during
546
+ the swap and continue to be associated with the respective objects that
547
+ they were protecting before the swap, if any. No protection epochs are
548
+ ended or initiated. — *end note*]
549
+
550
+ *Complexity:* Constant.
551
+
552
+ ##### Non-member functions <a id="saferecl.hp.holder.nonmem">[[saferecl.hp.holder.nonmem]]</a>
553
+
554
+ ``` cpp
555
+ hazard_pointer make_hazard_pointer();
556
+ ```
557
+
558
+ *Effects:* Constructs a hazard pointer.
559
+
560
+ *Returns:* A `hazard_pointer` object that owns the newly-constructed
561
+ hazard pointer.
562
+
563
+ *Throws:* May throw `bad_alloc` if memory for the hazard pointer could
564
+ not be allocated.
565
+
566
+ ``` cpp
567
+ void swap(hazard_pointer& a, hazard_pointer& b) noexcept;
568
+ ```
569
+
570
+ *Effects:* Equivalent to `a.swap(b)`.
571
+
572
+ <!-- Link reference definitions -->
573
+ [alg.min.max]: algorithms.md#alg.min.max
574
+ [alg.sorting]: algorithms.md#alg.sorting
575
+ [allocator.requirements.general]: library.md#allocator.requirements.general
576
+ [atomic.types.int.comp]: #atomic.types.int.comp
577
+ [atomic.types.pointer.comp]: #atomic.types.pointer.comp
578
+ [atomics]: #atomics
579
+ [atomics.alias]: #atomics.alias
580
+ [atomics.fences]: #atomics.fences
581
+ [atomics.flag]: #atomics.flag
582
+ [atomics.general]: #atomics.general
583
+ [atomics.lockfree]: #atomics.lockfree
584
+ [atomics.nonmembers]: #atomics.nonmembers
585
+ [atomics.order]: #atomics.order
586
+ [atomics.ref.float]: #atomics.ref.float
587
+ [atomics.ref.generic]: #atomics.ref.generic
588
+ [atomics.ref.generic.general]: #atomics.ref.generic.general
589
+ [atomics.ref.int]: #atomics.ref.int
590
+ [atomics.ref.memop]: #atomics.ref.memop
591
+ [atomics.ref.ops]: #atomics.ref.ops
592
+ [atomics.ref.pointer]: #atomics.ref.pointer
593
+ [atomics.syn]: #atomics.syn
594
+ [atomics.types.float]: #atomics.types.float
595
+ [atomics.types.generic]: #atomics.types.generic
596
+ [atomics.types.generic.general]: #atomics.types.generic.general
597
+ [atomics.types.int]: #atomics.types.int
598
+ [atomics.types.memop]: #atomics.types.memop
599
+ [atomics.types.operations]: #atomics.types.operations
600
+ [atomics.types.pointer]: #atomics.types.pointer
601
+ [atomics.wait]: #atomics.wait
602
+ [barrier.syn]: #barrier.syn
603
+ [basic.align]: basic.md#basic.align
604
+ [basic.fundamental]: basic.md#basic.fundamental
605
+ [basic.life]: basic.md#basic.life
606
+ [basic.stc.general]: basic.md#basic.stc.general
607
+ [basic.stc.thread]: basic.md#basic.stc.thread
608
+ [bitmask.types]: library.md#bitmask.types
609
+ [cfenv]: numerics.md#cfenv
610
+ [class.prop]: class.md#class.prop
611
+ [compliance]: library.md#compliance
612
+ [concept.booleantestable]: concepts.md#concept.booleantestable
613
+ [condition.variable.syn]: #condition.variable.syn
614
+ [conv.rval]: expr.md#conv.rval
615
+ [cpp17.defaultconstructible]: #cpp17.defaultconstructible
616
+ [cpp17.destructible]: #cpp17.destructible
617
+ [cpp17.lessthancomparable]: #cpp17.lessthancomparable
618
+ [cpp17.moveassignable]: #cpp17.moveassignable
619
+ [cpp17.moveconstructible]: #cpp17.moveconstructible
620
+ [defns.block]: intro.md#defns.block
621
+ [except.terminate]: except.md#except.terminate
622
+ [expr.pre]: expr.md#expr.pre
623
+ [expr.rel]: expr.md#expr.rel
624
+ [format.string.std]: text.md#format.string.std
625
+ [func.invoke]: utilities.md#func.invoke
626
+ [func.require]: utilities.md#func.require
627
+ [function.objects]: utilities.md#function.objects
628
+ [future.syn]: #future.syn
629
+ [futures]: #futures
630
+ [futures.async]: #futures.async
631
+ [futures.errors]: #futures.errors
632
+ [futures.future.error]: #futures.future.error
633
+ [futures.overview]: #futures.overview
634
+ [futures.promise]: #futures.promise
635
+ [futures.shared.future]: #futures.shared.future
636
+ [futures.state]: #futures.state
637
+ [futures.task]: #futures.task
638
+ [futures.task.general]: #futures.task.general
639
+ [futures.task.members]: #futures.task.members
640
+ [futures.task.nonmembers]: #futures.task.nonmembers
641
+ [futures.unique.future]: #futures.unique.future
642
+ [hazard.pointer.syn]: #hazard.pointer.syn
643
+ [intro.multithread]: basic.md#intro.multithread
644
+ [intro.progress]: basic.md#intro.progress
645
+ [intro.races]: basic.md#intro.races
646
+ [latch.syn]: #latch.syn
647
+ [limits.syn]: support.md#limits.syn
648
+ [mutex.syn]: #mutex.syn
649
+ [rcu.syn]: #rcu.syn
650
+ [res.on.data.races]: library.md#res.on.data.races
651
+ [res.on.exception.handling]: library.md#res.on.exception.handling
652
+ [saferecl]: #saferecl
653
+ [saferecl.general]: #saferecl.general
654
+ [saferecl.hp]: #saferecl.hp
655
+ [saferecl.hp.base]: #saferecl.hp.base
656
+ [saferecl.hp.general]: #saferecl.hp.general
657
+ [saferecl.hp.holder]: #saferecl.hp.holder
658
+ [saferecl.hp.holder.ctor]: #saferecl.hp.holder.ctor
659
+ [saferecl.hp.holder.general]: #saferecl.hp.holder.general
660
+ [saferecl.hp.holder.mem]: #saferecl.hp.holder.mem
661
+ [saferecl.hp.holder.nonmem]: #saferecl.hp.holder.nonmem
662
+ [saferecl.rcu]: #saferecl.rcu
663
+ [saferecl.rcu.base]: #saferecl.rcu.base
664
+ [saferecl.rcu.domain]: #saferecl.rcu.domain
665
+ [saferecl.rcu.domain.func]: #saferecl.rcu.domain.func
666
+ [saferecl.rcu.domain.general]: #saferecl.rcu.domain.general
667
+ [saferecl.rcu.domain.members]: #saferecl.rcu.domain.members
668
+ [saferecl.rcu.general]: #saferecl.rcu.general
669
+ [semaphore.syn]: #semaphore.syn
670
+ [shared.mutex.syn]: #shared.mutex.syn
671
+ [stdatomic.h.syn]: #stdatomic.h.syn
672
+ [stopcallback]: #stopcallback
673
+ [stopcallback.cons]: #stopcallback.cons
674
+ [stopcallback.general]: #stopcallback.general
675
+ [stopcallback.inplace]: #stopcallback.inplace
676
+ [stopcallback.inplace.cons]: #stopcallback.inplace.cons
677
+ [stopcallback.inplace.general]: #stopcallback.inplace.general
678
+ [stopsource]: #stopsource
679
+ [stopsource.cons]: #stopsource.cons
680
+ [stopsource.general]: #stopsource.general
681
+ [stopsource.inplace]: #stopsource.inplace
682
+ [stopsource.inplace.cons]: #stopsource.inplace.cons
683
+ [stopsource.inplace.general]: #stopsource.inplace.general
684
+ [stopsource.inplace.mem]: #stopsource.inplace.mem
685
+ [stopsource.mem]: #stopsource.mem
686
+ [stoptoken]: #stoptoken
687
+ [stoptoken.concepts]: #stoptoken.concepts
688
+ [stoptoken.general]: #stoptoken.general
689
+ [stoptoken.inplace]: #stoptoken.inplace
690
+ [stoptoken.inplace.general]: #stoptoken.inplace.general
691
+ [stoptoken.inplace.mem]: #stoptoken.inplace.mem
692
+ [stoptoken.mem]: #stoptoken.mem
693
+ [stoptoken.never]: #stoptoken.never
694
+ [syserr]: diagnostics.md#syserr
695
+ [syserr.syserr]: diagnostics.md#syserr.syserr
696
+ [term.padding.bits]: basic.md#term.padding.bits
697
+ [term.unevaluated.operand]: expr.md#term.unevaluated.operand
698
+ [thread]: #thread
699
+ [thread.barrier]: #thread.barrier
700
+ [thread.barrier.class]: #thread.barrier.class
701
+ [thread.barrier.general]: #thread.barrier.general
702
+ [thread.condition]: #thread.condition
703
+ [thread.condition.condvar]: #thread.condition.condvar
704
+ [thread.condition.condvarany]: #thread.condition.condvarany
705
+ [thread.condition.condvarany.general]: #thread.condition.condvarany.general
706
+ [thread.condition.general]: #thread.condition.general
707
+ [thread.condition.nonmember]: #thread.condition.nonmember
708
+ [thread.condvarany.intwait]: #thread.condvarany.intwait
709
+ [thread.condvarany.wait]: #thread.condvarany.wait
710
+ [thread.coord]: #thread.coord
711
+ [thread.coord.general]: #thread.coord.general
712
+ [thread.general]: #thread.general
713
+ [thread.jthread.class]: #thread.jthread.class
714
+ [thread.jthread.class.general]: #thread.jthread.class.general
715
+ [thread.jthread.cons]: #thread.jthread.cons
716
+ [thread.jthread.mem]: #thread.jthread.mem
717
+ [thread.jthread.special]: #thread.jthread.special
718
+ [thread.jthread.static]: #thread.jthread.static
719
+ [thread.jthread.stop]: #thread.jthread.stop
720
+ [thread.latch]: #thread.latch
721
+ [thread.latch.class]: #thread.latch.class
722
+ [thread.latch.general]: #thread.latch.general
723
+ [thread.lock]: #thread.lock
724
+ [thread.lock.algorithm]: #thread.lock.algorithm
725
+ [thread.lock.general]: #thread.lock.general
726
+ [thread.lock.guard]: #thread.lock.guard
727
+ [thread.lock.scoped]: #thread.lock.scoped
728
+ [thread.lock.shared]: #thread.lock.shared
729
+ [thread.lock.shared.cons]: #thread.lock.shared.cons
730
+ [thread.lock.shared.general]: #thread.lock.shared.general
731
+ [thread.lock.shared.locking]: #thread.lock.shared.locking
732
+ [thread.lock.shared.mod]: #thread.lock.shared.mod
733
+ [thread.lock.shared.obs]: #thread.lock.shared.obs
734
+ [thread.lock.unique]: #thread.lock.unique
735
+ [thread.lock.unique.cons]: #thread.lock.unique.cons
736
+ [thread.lock.unique.general]: #thread.lock.unique.general
737
+ [thread.lock.unique.locking]: #thread.lock.unique.locking
738
+ [thread.lock.unique.mod]: #thread.lock.unique.mod
739
+ [thread.lock.unique.obs]: #thread.lock.unique.obs
740
+ [thread.mutex]: #thread.mutex
741
+ [thread.mutex.class]: #thread.mutex.class
742
+ [thread.mutex.general]: #thread.mutex.general
743
+ [thread.mutex.recursive]: #thread.mutex.recursive
744
+ [thread.mutex.requirements]: #thread.mutex.requirements
745
+ [thread.mutex.requirements.general]: #thread.mutex.requirements.general
746
+ [thread.mutex.requirements.mutex]: #thread.mutex.requirements.mutex
747
+ [thread.mutex.requirements.mutex.general]: #thread.mutex.requirements.mutex.general
748
+ [thread.once]: #thread.once
749
+ [thread.once.callonce]: #thread.once.callonce
750
+ [thread.once.onceflag]: #thread.once.onceflag
751
+ [thread.req]: #thread.req
752
+ [thread.req.exception]: #thread.req.exception
753
+ [thread.req.lockable]: #thread.req.lockable
754
+ [thread.req.lockable.basic]: #thread.req.lockable.basic
755
+ [thread.req.lockable.general]: #thread.req.lockable.general
756
+ [thread.req.lockable.req]: #thread.req.lockable.req
757
+ [thread.req.lockable.shared]: #thread.req.lockable.shared
758
+ [thread.req.lockable.shared.timed]: #thread.req.lockable.shared.timed
759
+ [thread.req.lockable.timed]: #thread.req.lockable.timed
760
+ [thread.req.native]: #thread.req.native
761
+ [thread.req.paramname]: #thread.req.paramname
762
+ [thread.req.timing]: #thread.req.timing
763
+ [thread.sema]: #thread.sema
764
+ [thread.sema.cnt]: #thread.sema.cnt
765
+ [thread.sema.general]: #thread.sema.general
766
+ [thread.sharedmutex.class]: #thread.sharedmutex.class
767
+ [thread.sharedmutex.requirements]: #thread.sharedmutex.requirements
768
+ [thread.sharedmutex.requirements.general]: #thread.sharedmutex.requirements.general
769
+ [thread.sharedtimedmutex.class]: #thread.sharedtimedmutex.class
770
+ [thread.sharedtimedmutex.requirements]: #thread.sharedtimedmutex.requirements
771
+ [thread.sharedtimedmutex.requirements.general]: #thread.sharedtimedmutex.requirements.general
772
+ [thread.stoptoken]: #thread.stoptoken
773
+ [thread.stoptoken.intro]: #thread.stoptoken.intro
774
+ [thread.stoptoken.syn]: #thread.stoptoken.syn
775
+ [thread.summary]: #thread.summary
776
+ [thread.syn]: #thread.syn
777
+ [thread.thread.algorithm]: #thread.thread.algorithm
778
+ [thread.thread.assign]: #thread.thread.assign
779
+ [thread.thread.class]: #thread.thread.class
780
+ [thread.thread.class.general]: #thread.thread.class.general
781
+ [thread.thread.constr]: #thread.thread.constr
782
+ [thread.thread.destr]: #thread.thread.destr
783
+ [thread.thread.id]: #thread.thread.id
784
+ [thread.thread.member]: #thread.thread.member
785
+ [thread.thread.static]: #thread.thread.static
786
+ [thread.thread.this]: #thread.thread.this
787
+ [thread.threads]: #thread.threads
788
+ [thread.threads.general]: #thread.threads.general
789
+ [thread.timedmutex.class]: #thread.timedmutex.class
790
+ [thread.timedmutex.recursive]: #thread.timedmutex.recursive
791
+ [thread.timedmutex.requirements]: #thread.timedmutex.requirements
792
+ [thread.timedmutex.requirements.general]: #thread.timedmutex.requirements.general
793
+ [time]: time.md#time
794
+ [time.clock]: time.md#time.clock
795
+ [time.clock.req]: time.md#time.clock.req
796
+ [time.duration]: time.md#time.duration
797
+ [time.point]: time.md#time.point
798
+ [unord.hash]: utilities.md#unord.hash
799
+ [util.sharedptr]: mem.md#util.sharedptr
800
+ [util.smartptr.atomic]: #util.smartptr.atomic
801
+ [util.smartptr.atomic.general]: #util.smartptr.atomic.general
802
+ [util.smartptr.atomic.shared]: #util.smartptr.atomic.shared
803
+ [util.smartptr.atomic.weak]: #util.smartptr.atomic.weak
804
+
805
+ [^1]: Implementations for which standard time units are meaningful will
806
+ typically have a steady clock within their hardware implementation.
807
+
808
+ [^2]: That is, atomic operations on the same memory location via two
809
+ different addresses will communicate atomically.