From Jason Turner

[thread.mutex]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp2hkky5kp/{from.md → to.md} +325 -372
tmp/tmp2hkky5kp/{from.md → to.md} RENAMED
@@ -1,10 +1,10 @@
1
  ## Mutual exclusion <a id="thread.mutex">[[thread.mutex]]</a>
2
 
3
- This section provides mechanisms for mutual exclusion: mutexes, locks,
4
  and call once. These mechanisms ease the production of race-free
5
- programs ([[intro.multithread]]).
6
 
7
  ### Header `<mutex>` synopsis <a id="mutex.syn">[[mutex.syn]]</a>
8
 
9
  ``` cpp
10
  namespace std {
@@ -36,11 +36,11 @@ namespace std {
36
  template<class Callable, class... Args>
37
  void call_once(once_flag& flag, Callable&& func, Args&&... args);
38
  }
39
  ```
40
 
41
- ### Header `<shared_mutex>` synopsis <a id="shared_mutex.syn">[[shared_mutex.syn]]</a>
42
 
43
  ``` cpp
44
  namespace std {
45
  class shared_mutex;
46
  class shared_timed_mutex;
@@ -53,128 +53,129 @@ namespace std {
53
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
54
 
55
  #### In general <a id="thread.mutex.requirements.general">[[thread.mutex.requirements.general]]</a>
56
 
57
  A mutex object facilitates protection against data races and allows safe
58
- synchronization of data between execution agents (
59
- [[thread.req.lockable]]). An execution agent *owns* a mutex from the
60
- time it successfully calls one of the lock functions until it calls
61
- unlock. Mutexes can be either recursive or non-recursive, and can grant
62
  simultaneous ownership to one or many execution agents. Both recursive
63
  and non-recursive mutexes are supplied.
64
 
65
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
66
 
67
  The *mutex types* are the standard library types `mutex`,
68
  `recursive_mutex`, `timed_mutex`, `recursive_timed_mutex`,
69
- `shared_mutex`, and `shared_timed_mutex`. They shall meet the
70
- requirements set out in this section. In this description, `m` denotes
71
- an object of a mutex type.
72
 
73
- The mutex types shall meet the `Lockable` requirements (
74
- [[thread.req.lockable.req]]).
75
 
76
- The mutex types shall be `DefaultConstructible` and `Destructible`. If
77
- initialization of an object of a mutex type fails, an exception of type
78
- `system_error` shall be thrown. The mutex types shall not be copyable or
79
- movable.
80
 
81
  The error conditions for error codes, if any, reported by member
82
- functions of the mutex types shall be:
83
 
84
  - `resource_unavailable_try_again` — if any native handle type
85
  manipulated is not available.
86
  - `operation_not_permitted` — if the thread does not have the privilege
87
  to perform the operation.
88
  - `invalid_argument` — if any native handle type manipulated as part of
89
  mutex construction is incorrect.
90
 
91
- The implementation shall provide lock and unlock operations, as
92
- described below. For purposes of determining the existence of a data
93
- race, these behave as atomic operations ([[intro.multithread]]). The
94
- lock and unlock operations on a single mutex shall appear to occur in a
95
- single total order.
96
 
97
- [*Note 1*: This can be viewed as the modification order (
98
- [[intro.multithread]]) of the mutex. — *end note*]
99
 
100
  [*Note 2*: Construction and destruction of an object of a mutex type
101
  need not be thread-safe; other synchronization should be used to ensure
102
  that mutex objects are initialized and visible to other
103
  threads. — *end note*]
104
 
105
- The expression `m.lock()` shall be well-formed and have the following
106
  semantics:
107
 
108
- *Requires:* If `m` is of type `mutex`, `timed_mutex`, `shared_mutex`, or
109
- `shared_timed_mutex`, the calling thread does not own the mutex.
 
110
 
111
  *Effects:* Blocks the calling thread until ownership of the mutex can be
112
  obtained for the calling thread.
113
 
114
- *Postconditions:* The calling thread owns the mutex.
115
 
116
  *Return type:* `void`.
117
 
118
- *Synchronization:* Prior `unlock()` operations on the same object shall
119
- *synchronize with* ([[intro.multithread]]) this operation.
120
 
121
  *Throws:* `system_error` when an exception is
122
- required ([[thread.req.exception]]).
123
 
124
  *Error conditions:*
125
 
126
  - `operation_not_permitted` — if the thread does not have the privilege
127
  to perform the operation.
128
  - `resource_deadlock_would_occur` — if the implementation detects that a
129
  deadlock would occur.
130
 
131
- The expression `m.try_lock()` shall be well-formed and have the
132
- following semantics:
133
 
134
- *Requires:* If `m` is of type `mutex`, `timed_mutex`, `shared_mutex`, or
135
- `shared_timed_mutex`, the calling thread does not own the mutex.
 
136
 
137
  *Effects:* Attempts to obtain ownership of the mutex for the calling
138
  thread without blocking. If ownership is not obtained, there is no
139
  effect and `try_lock()` immediately returns. An implementation may fail
140
  to obtain the lock even if it is not held by any other thread.
141
 
142
  [*Note 1*: This spurious failure is normally uncommon, but allows
143
- interesting implementations based on a simple compare and exchange
144
- (Clause  [[atomics]]). — *end note*]
145
 
146
  An implementation should ensure that `try_lock()` does not consistently
147
  return `false` in the absence of contending mutex acquisitions.
148
 
149
  *Return type:* `bool`.
150
 
151
  *Returns:* `true` if ownership of the mutex was obtained for the calling
152
  thread, otherwise `false`.
153
 
154
  *Synchronization:* If `try_lock()` returns `true`, prior `unlock()`
155
- operations on the same object *synchronize
156
- with* ([[intro.multithread]]) this operation.
157
 
158
  [*Note 2*: Since `lock()` does not synchronize with a failed subsequent
159
  `try_lock()`, the visibility rules are weak enough that little would be
160
  known about the state after a failure, even in the absence of spurious
161
  failures. — *end note*]
162
 
163
  *Throws:* Nothing.
164
 
165
- The expression `m.unlock()` shall be well-formed and have the following
166
  semantics:
167
 
168
- *Requires:* The calling thread shall own the mutex.
169
 
170
  *Effects:* Releases the calling thread’s ownership of the mutex.
171
 
172
  *Return type:* `void`.
173
 
174
  *Synchronization:* This operation synchronizes
175
- with ([[intro.multithread]]) subsequent lock operations that obtain
176
  ownership on the same object.
177
 
178
  *Throws:* Nothing.
179
 
180
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
@@ -191,12 +192,12 @@ namespace std {
191
 
192
  void lock();
193
  bool try_lock();
194
  void unlock();
195
 
196
- using native_handle_type = implementation-defined; // See~[thread.req.native]
197
- native_handle_type native_handle(); // See~[thread.req.native]
198
  };
199
  }
200
  ```
201
 
202
  The class `mutex` provides a non-recursive mutex with exclusive
@@ -212,17 +213,17 @@ that it is no longer in use, unlock it, and destroy it, before thread
212
  required to handle such scenarios correctly, as long as thread `A`
213
  doesn’t access the mutex after the unlock call returns. These cases
214
  typically occur when a reference-counted object contains a mutex that is
215
  used to protect the reference count. — *end note*]
216
 
217
- The class `mutex` shall satisfy all of the mutex requirements (
218
- [[thread.mutex.requirements]]). It shall be a standard-layout class
219
- (Clause  [[class]]).
220
 
221
- [*Note 4*: A program may deadlock if the thread that owns a `mutex`
222
  object calls `lock()` on that object. If the implementation can detect
223
- the deadlock, a `resource_deadlock_would_occur` error condition may be
224
  observed. — *end note*]
225
 
226
  The behavior of a program is undefined if it destroys a `mutex` object
227
  owned by any thread or a thread terminates while owning a `mutex`
228
  object.
@@ -241,92 +242,92 @@ namespace std {
241
 
242
  void lock();
243
  bool try_lock() noexcept;
244
  void unlock();
245
 
246
- using native_handle_type = implementation-defined; // See~[thread.req.native]
247
- native_handle_type native_handle(); // See~[thread.req.native]
248
  };
249
  }
250
  ```
251
 
252
  The class `recursive_mutex` provides a recursive mutex with exclusive
253
  ownership semantics. If one thread owns a `recursive_mutex` object,
254
  attempts by another thread to acquire ownership of that object will fail
255
  (for `try_lock()`) or block (for `lock()`) until the first thread has
256
  completely released ownership.
257
 
258
- The class `recursive_mutex` shall satisfy all of the mutex
259
- requirements ([[thread.mutex.requirements]]). It shall be a
260
- standard-layout class (Clause  [[class]]).
261
 
262
  A thread that owns a `recursive_mutex` object may acquire additional
263
  levels of ownership by calling `lock()` or `try_lock()` on that object.
264
  It is unspecified how many levels of ownership may be acquired by a
265
  single thread. If a thread has already acquired the maximum level of
266
  ownership for a `recursive_mutex` object, additional calls to
267
- `try_lock()` shall fail, and additional calls to `lock()` shall throw an
268
- exception of type `system_error`. A thread shall call `unlock()` once
269
- for each level of ownership acquired by calls to `lock()` and
270
- `try_lock()`. Only when all levels of ownership have been released may
271
- ownership be acquired by another thread.
272
 
273
  The behavior of a program is undefined if:
274
 
275
  - it destroys a `recursive_mutex` object owned by any thread or
276
  - a thread terminates while owning a `recursive_mutex` object.
277
 
278
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
279
 
280
  The *timed mutex types* are the standard library types `timed_mutex`,
281
- `recursive_timed_mutex`, and `shared_timed_mutex`. They shall meet the
282
  requirements set out below. In this description, `m` denotes an object
283
  of a mutex type, `rel_time` denotes an object of an instantiation of
284
- `duration` ([[time.duration]]), and `abs_time` denotes an object of an
285
- instantiation of `time_point` ([[time.point]]).
286
 
287
- The timed mutex types shall meet the `TimedLockable` requirements (
288
- [[thread.req.lockable.timed]]).
289
 
290
- The expression `m.try_lock_for(rel_time)` shall be well-formed and have
291
- the following semantics:
292
 
293
- *Requires:* If `m` is of type `timed_mutex` or `shared_timed_mutex`, the
294
- calling thread does not own the mutex.
295
 
296
  *Effects:* The function attempts to obtain ownership of the mutex within
297
- the relative timeout ([[thread.req.timing]]) specified by `rel_time`.
298
- If the time specified by `rel_time` is less than or equal to
299
  `rel_time.zero()`, the function attempts to obtain ownership without
300
- blocking (as if by calling `try_lock()`). The function shall return
301
- within the timeout specified by `rel_time` only if it has obtained
302
- ownership of the mutex object.
303
 
304
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
305
  will be obtained if the lock is available, but implementations are
306
  expected to make a strong effort to do so. — *end note*]
307
 
308
  *Return type:* `bool`.
309
 
310
  *Returns:* `true` if ownership was obtained, otherwise `false`.
311
 
312
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
313
- operations on the same object *synchronize
314
- with* ([[intro.multithread]]) this operation.
315
 
316
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
317
 
318
- The expression `m.try_lock_until(abs_time)` shall be well-formed and
319
- have the following semantics:
320
 
321
- *Requires:* If `m` is of type `timed_mutex` or `shared_timed_mutex`, the
322
- calling thread does not own the mutex.
323
 
324
  *Effects:* The function attempts to obtain ownership of the mutex. If
325
  `abs_time` has already passed, the function attempts to obtain ownership
326
- without blocking (as if by calling `try_lock()`). The function shall
327
- return before the absolute timeout ([[thread.req.timing]]) specified by
328
  `abs_time` only if it has obtained ownership of the mutex object.
329
 
330
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
331
  will be obtained if the lock is available, but implementations are
332
  expected to make a strong effort to do so. — *end note*]
@@ -335,13 +336,13 @@ expected to make a strong effort to do so. — *end note*]
335
 
336
  *Returns:* `true` if ownership was obtained, otherwise `false`.
337
 
338
  *Synchronization:* If `try_lock_until()` returns `true`, prior
339
  `unlock()` operations on the same object *synchronize
340
- with* ([[intro.multithread]]) this operation.
341
 
342
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
343
 
344
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
345
 
346
  ``` cpp
347
  namespace std {
@@ -359,12 +360,12 @@ namespace std {
359
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
360
  template<class Clock, class Duration>
361
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
362
  void unlock();
363
 
364
- using native_handle_type = implementation-defined; // See~[thread.req.native]
365
- native_handle_type native_handle(); // See~[thread.req.native]
366
  };
367
  }
368
  ```
369
 
370
  The class `timed_mutex` provides a non-recursive mutex with exclusive
@@ -373,13 +374,13 @@ by another thread to acquire ownership of that object will fail (for
373
  `try_lock()`) or block (for `lock()`, `try_lock_for()`, and
374
  `try_lock_until()`) until the owning thread has released ownership with
375
  a call to `unlock()` or the call to `try_lock_for()` or
376
  `try_lock_until()` times out (having failed to obtain ownership).
377
 
378
- The class `timed_mutex` shall satisfy all of the timed mutex
379
- requirements ([[thread.timedmutex.requirements]]). It shall be a
380
- standard-layout class (Clause  [[class]]).
381
 
382
  The behavior of a program is undefined if:
383
 
384
  - it destroys a `timed_mutex` object owned by any thread,
385
  - a thread that owns a `timed_mutex` object calls `lock()`,
@@ -405,12 +406,12 @@ namespace std {
405
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
406
  template<class Clock, class Duration>
407
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
408
  void unlock();
409
 
410
- using native_handle_type = implementation-defined; // See~[thread.req.native]
411
- native_handle_type native_handle(); // See~[thread.req.native]
412
  };
413
  }
414
  ```
415
 
416
  The class `recursive_timed_mutex` provides a recursive mutex with
@@ -419,99 +420,99 @@ exclusive ownership semantics. If one thread owns a
419
  ownership of that object will fail (for `try_lock()`) or block (for
420
  `lock()`, `try_lock_for()`, and `try_lock_until()`) until the owning
421
  thread has completely released ownership or the call to `try_lock_for()`
422
  or `try_lock_until()` times out (having failed to obtain ownership).
423
 
424
- The class `recursive_timed_mutex` shall satisfy all of the timed mutex
425
- requirements ([[thread.timedmutex.requirements]]). It shall be a
426
- standard-layout class (Clause  [[class]]).
427
 
428
  A thread that owns a `recursive_timed_mutex` object may acquire
429
  additional levels of ownership by calling `lock()`, `try_lock()`,
430
  `try_lock_for()`, or `try_lock_until()` on that object. It is
431
  unspecified how many levels of ownership may be acquired by a single
432
  thread. If a thread has already acquired the maximum level of ownership
433
  for a `recursive_timed_mutex` object, additional calls to `try_lock()`,
434
- `try_lock_for()`, or `try_lock_until()` shall fail, and additional calls
435
- to `lock()` shall throw an exception of type `system_error`. A thread
436
- shall call `unlock()` once for each level of ownership acquired by calls
437
- to `lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`.
438
- Only when all levels of ownership have been released may ownership of
439
- the object be acquired by another thread.
440
 
441
  The behavior of a program is undefined if:
442
 
443
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
444
  - a thread terminates while owning a `recursive_timed_mutex` object.
445
 
446
  #### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
447
 
448
  The standard library types `shared_mutex` and `shared_timed_mutex` are
449
- *shared mutex types*. Shared mutex types shall meet the requirements of
450
- mutex types ([[thread.mutex.requirements.mutex]]), and additionally
451
- shall meet the requirements set out below. In this description, `m`
452
- denotes an object of a shared mutex type.
453
 
454
  In addition to the exclusive lock ownership mode specified in 
455
  [[thread.mutex.requirements.mutex]], shared mutex types provide a
456
  *shared lock* ownership mode. Multiple execution agents can
457
  simultaneously hold a shared lock ownership of a shared mutex type. But
458
- no execution agent shall hold a shared lock while another execution
459
- agent holds an exclusive lock on the same shared mutex type, and
460
- vice-versa. The maximum number of execution agents which can share a
461
- shared lock on a single shared mutex type is unspecified, but shall be
462
- at least 10000. If more than the maximum number of execution agents
463
- attempt to obtain a shared lock, the excess execution agents shall block
464
- until the number of shared locks are reduced below the maximum amount by
465
- other execution agents releasing their shared lock.
466
 
467
- The expression `m.lock_shared()` shall be well-formed and have the
468
- following semantics:
469
 
470
- *Requires:* The calling thread has no ownership of the mutex.
471
 
472
  *Effects:* Blocks the calling thread until shared ownership of the mutex
473
  can be obtained for the calling thread. If an exception is thrown then a
474
- shared lock shall not have been acquired for the current thread.
475
 
476
- *Postconditions:* The calling thread has a shared lock on the mutex.
477
 
478
  *Return type:* `void`.
479
 
480
- *Synchronization:* Prior `unlock()` operations on the same object shall
481
- synchronize with ([[intro.multithread]]) this operation.
482
 
483
  *Throws:* `system_error` when an exception is
484
- required ([[thread.req.exception]]).
485
 
486
  *Error conditions:*
487
 
488
  - `operation_not_permitted` — if the thread does not have the privilege
489
  to perform the operation.
490
  - `resource_deadlock_would_occur` — if the implementation detects that a
491
  deadlock would occur.
492
 
493
- The expression `m.unlock_shared()` shall be well-formed and have the
494
- following semantics:
495
 
496
- *Requires:* The calling thread shall hold a shared lock on the mutex.
497
 
498
  *Effects:* Releases a shared lock on the mutex held by the calling
499
  thread.
500
 
501
  *Return type:* `void`.
502
 
503
  *Synchronization:* This operation synchronizes
504
- with ([[intro.multithread]]) subsequent `lock()` operations that obtain
505
  ownership on the same object.
506
 
507
  *Throws:* Nothing.
508
 
509
- The expression `m.try_lock_shared()` shall be well-formed and have the
510
  following semantics:
511
 
512
- *Requires:* The calling thread has no ownership of the mutex.
513
 
514
  *Effects:* Attempts to obtain shared ownership of the mutex for the
515
  calling thread without blocking. If shared ownership is not obtained,
516
  there is no effect and `try_lock_shared()` immediately returns. An
517
  implementation may fail to obtain the lock even if it is not held by any
@@ -522,15 +523,15 @@ other thread.
522
  *Returns:* `true` if the shared ownership lock was acquired, `false`
523
  otherwise.
524
 
525
  *Synchronization:* If `try_lock_shared()` returns `true`, prior
526
  `unlock()` operations on the same object synchronize
527
- with ([[intro.multithread]]) this operation.
528
 
529
  *Throws:* Nothing.
530
 
531
- ##### Class shared_mutex <a id="thread.sharedmutex.class">[[thread.sharedmutex.class]]</a>
532
 
533
  ``` cpp
534
  namespace std {
535
  class shared_mutex {
536
  public:
@@ -538,32 +539,32 @@ namespace std {
538
  ~shared_mutex();
539
 
540
  shared_mutex(const shared_mutex&) = delete;
541
  shared_mutex& operator=(const shared_mutex&) = delete;
542
 
543
- // Exclusive ownership
544
  void lock(); // blocking
545
  bool try_lock();
546
  void unlock();
547
 
548
- // Shared ownership
549
  void lock_shared(); // blocking
550
  bool try_lock_shared();
551
  void unlock_shared();
552
 
553
- using native_handle_type = implementation-defined; // See~[thread.req.native]
554
- native_handle_type native_handle(); // See~[thread.req.native]
555
  };
556
  }
557
  ```
558
 
559
  The class `shared_mutex` provides a non-recursive mutex with shared
560
  ownership semantics.
561
 
562
- The class `shared_mutex` shall satisfy all of the shared mutex
563
- requirements ([[thread.sharedmutex.requirements]]). It shall be a
564
- standard-layout class (Clause  [[class]]).
565
 
566
  The behavior of a program is undefined if:
567
 
568
  - it destroys a `shared_mutex` object owned by any thread,
569
  - a thread attempts to recursively gain any ownership of a
@@ -574,76 +575,76 @@ The behavior of a program is undefined if:
574
  `shared_mutex` may be a synonym for `shared_timed_mutex`.
575
 
576
  #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
577
 
578
  The standard library type `shared_timed_mutex` is a *shared timed mutex
579
- type*. Shared timed mutex types shall meet the requirements of timed
580
- mutex types ([[thread.timedmutex.requirements]]), shared mutex types (
581
- [[thread.sharedmutex.requirements]]), and additionally shall meet the
582
  requirements set out below. In this description, `m` denotes an object
583
  of a shared timed mutex type, `rel_type` denotes an object of an
584
- instantiation of `duration` ([[time.duration]]), and `abs_time` denotes
585
- an object of an instantiation of `time_point` ([[time.point]]).
586
 
587
- The expression `m.try_lock_shared_for(rel_time)` shall be well-formed
588
- and have the following semantics:
589
 
590
- *Requires:* The calling thread has no ownership of the mutex.
591
 
592
  *Effects:* Attempts to obtain shared lock ownership for the calling
593
- thread within the relative timeout ([[thread.req.timing]]) specified by
594
  `rel_time`. If the time specified by `rel_time` is less than or equal to
595
  `rel_time.zero()`, the function attempts to obtain ownership without
596
- blocking (as if by calling `try_lock_shared()`). The function shall
597
- return within the timeout specified by `rel_time` only if it has
598
- obtained shared ownership of the mutex object.
599
 
600
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
601
  will be obtained if the lock is available, but implementations are
602
  expected to make a strong effort to do so. — *end note*]
603
 
604
- If an exception is thrown then a shared lock shall not have been
605
- acquired for the current thread.
606
 
607
  *Return type:* `bool`.
608
 
609
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
610
 
611
  *Synchronization:* If `try_lock_shared_for()` returns `true`, prior
612
  `unlock()` operations on the same object synchronize
613
- with ([[intro.multithread]]) this operation.
614
 
615
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
616
 
617
- The expression `m.try_lock_shared_until(abs_time)` shall be well-formed
618
- and have the following semantics:
619
 
620
- *Requires:* The calling thread has no ownership of the mutex.
621
 
622
  *Effects:* The function attempts to obtain shared ownership of the
623
  mutex. If `abs_time` has already passed, the function attempts to obtain
624
  shared ownership without blocking (as if by calling
625
- `try_lock_shared()`). The function shall return before the absolute
626
- timeout ([[thread.req.timing]]) specified by `abs_time` only if it has
627
  obtained shared ownership of the mutex object.
628
 
629
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
630
  will be obtained if the lock is available, but implementations are
631
  expected to make a strong effort to do so. — *end note*]
632
 
633
- If an exception is thrown then a shared lock shall not have been
634
- acquired for the current thread.
635
 
636
  *Return type:* `bool`.
637
 
638
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
639
 
640
  *Synchronization:* If `try_lock_shared_until()` returns `true`, prior
641
  `unlock()` operations on the same object synchronize
642
- with ([[intro.multithread]]) this operation.
643
 
644
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
645
 
646
  ##### Class `shared_timed_mutex` <a id="thread.sharedtimedmutex.class">[[thread.sharedtimedmutex.class]]</a>
647
 
648
  ``` cpp
649
  namespace std {
@@ -653,39 +654,37 @@ namespace std {
653
  ~shared_timed_mutex();
654
 
655
  shared_timed_mutex(const shared_timed_mutex&) = delete;
656
  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
657
 
658
- // Exclusive ownership
659
  void lock(); // blocking
660
  bool try_lock();
661
  template<class Rep, class Period>
662
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
663
  template<class Clock, class Duration>
664
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
665
  void unlock();
666
 
667
- // Shared ownership
668
  void lock_shared(); // blocking
669
  bool try_lock_shared();
670
  template<class Rep, class Period>
671
- bool
672
- try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
673
  template<class Clock, class Duration>
674
- bool
675
- try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
676
  void unlock_shared();
677
  };
678
  }
679
  ```
680
 
681
  The class `shared_timed_mutex` provides a non-recursive mutex with
682
  shared ownership semantics.
683
 
684
- The class `shared_timed_mutex` shall satisfy all of the shared timed
685
- mutex requirements ([[thread.sharedtimedmutex.requirements]]). It shall
686
- be a standard-layout class (Clause  [[class]]).
687
 
688
  The behavior of a program is undefined if:
689
 
690
  - it destroys a `shared_timed_mutex` object owned by any thread,
691
  - a thread attempts to recursively gain any ownership of a
@@ -741,41 +740,37 @@ namespace std {
741
  lock_guard& operator=(const lock_guard&) = delete;
742
 
743
  private:
744
  mutex_type& pm; // exposition only
745
  };
746
-
747
- template<class Mutex> lock_guard(lock_guard<Mutex>) -> lock_guard<Mutex>;
748
  }
749
  ```
750
 
751
  An object of type `lock_guard` controls the ownership of a lockable
752
  object within a scope. A `lock_guard` object maintains ownership of a
753
- lockable object throughout the `lock_guard` object’s lifetime (
754
- [[basic.life]]). The behavior of a program is undefined if the lockable
755
  object referenced by `pm` does not exist for the entire lifetime of the
756
  `lock_guard` object. The supplied `Mutex` type shall meet the
757
- `BasicLockable` requirements ([[thread.req.lockable.basic]]).
758
 
759
  ``` cpp
760
  explicit lock_guard(mutex_type& m);
761
  ```
762
 
763
- *Requires:* If `mutex_type` is not a recursive mutex, the calling thread
764
- does not own the mutex `m`.
765
 
766
- *Effects:* As if by `m.lock()`.
767
-
768
- *Postconditions:* `&pm == &m`
769
 
770
  ``` cpp
771
  lock_guard(mutex_type& m, adopt_lock_t);
772
  ```
773
 
774
- *Requires:* The calling thread owns the mutex `m`.
775
 
776
- *Postconditions:* `&pm == &m`
777
 
778
  *Throws:* Nothing.
779
 
780
  ``` cpp
781
  ~lock_guard();
@@ -791,52 +786,49 @@ namespace std {
791
  class scoped_lock {
792
  public:
793
  using mutex_type = Mutex; // If MutexTypes... consists of the single type Mutex
794
 
795
  explicit scoped_lock(MutexTypes&... m);
796
- explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
797
  ~scoped_lock();
798
 
799
  scoped_lock(const scoped_lock&) = delete;
800
  scoped_lock& operator=(const scoped_lock&) = delete;
801
 
802
  private:
803
  tuple<MutexTypes&...> pm; // exposition only
804
  };
805
-
806
- template<class... MutexTypes>
807
- scoped_lock(scoped_lock<MutexTypes...>) -> scoped_lock<MutexTypes...>;
808
  }
809
  ```
810
 
811
  An object of type `scoped_lock` controls the ownership of lockable
812
  objects within a scope. A `scoped_lock` object maintains ownership of
813
- lockable objects throughout the `scoped_lock` object’s lifetime (
814
- [[basic.life]]). The behavior of a program is undefined if the lockable
815
  objects referenced by `pm` do not exist for the entire lifetime of the
816
  `scoped_lock` object. When `sizeof...(MutexTypes)` is `1`, the supplied
817
- `Mutex` type shall meet the `BasicLockable` requirements (
818
- [[thread.req.lockable.basic]]). Otherwise, each of the mutex types shall
819
- meet the `Lockable` requirements ([[thread.req.lockable.req]]).
820
 
821
  ``` cpp
822
  explicit scoped_lock(MutexTypes&... m);
823
  ```
824
 
825
- *Requires:* If a `MutexTypes` type is not a recursive mutex, the calling
826
- thread does not own the corresponding mutex element of `m`.
827
 
828
  *Effects:* Initializes `pm` with `tie(m...)`. Then if
829
  `sizeof...(MutexTypes)` is `0`, no effects. Otherwise if
830
  `sizeof...(MutexTypes)` is `1`, then `m.lock()`. Otherwise,
831
  `lock(m...)`.
832
 
833
  ``` cpp
834
- explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
835
  ```
836
 
837
- *Requires:* The calling thread owns all the mutexes in `m`.
838
 
839
  *Effects:* Initializes `pm` with `tie(m...)`.
840
 
841
  *Throws:* Nothing.
842
 
@@ -897,12 +889,10 @@ namespace std {
897
  private:
898
  mutex_type* pm; // exposition only
899
  bool owns; // exposition only
900
  };
901
 
902
- template<class Mutex> unique_lock(unique_lock<Mutex>) -> unique_lock<Mutex>;
903
-
904
  template<class Mutex>
905
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
906
  }
907
  ```
908
 
@@ -911,123 +901,113 @@ object within a scope. Ownership of the lockable object may be acquired
911
  at construction or after construction, and may be transferred, after
912
  acquisition, to another `unique_lock` object. Objects of type
913
  `unique_lock` are not copyable but are movable. The behavior of a
914
  program is undefined if the contained pointer `pm` is not null and the
915
  lockable object pointed to by `pm` does not exist for the entire
916
- remaining lifetime ([[basic.life]]) of the `unique_lock` object. The
917
- supplied `Mutex` type shall meet the `BasicLockable` requirements (
918
- [[thread.req.lockable.basic]]).
919
 
920
- [*Note 1*: `unique_lock<Mutex>` meets the `BasicLockable` requirements.
921
- If `Mutex` meets the `Lockable` requirements (
922
- [[thread.req.lockable.req]]), `unique_lock<Mutex>` also meets the
923
- `Lockable` requirements; if `Mutex` meets the `TimedLockable`
924
- requirements ([[thread.req.lockable.timed]]), `unique_lock<Mutex>` also
925
- meets the `TimedLockable` requirements. — *end note*]
926
 
927
- ##### `unique_lock` constructors, destructor, and assignment <a id="thread.lock.unique.cons">[[thread.lock.unique.cons]]</a>
928
 
929
  ``` cpp
930
  unique_lock() noexcept;
931
  ```
932
 
933
- *Effects:* Constructs an object of type `unique_lock`.
934
-
935
- *Postconditions:* `pm == 0` and `owns == false`.
936
 
937
  ``` cpp
938
  explicit unique_lock(mutex_type& m);
939
  ```
940
 
941
- *Requires:* If `mutex_type` is not a recursive mutex the calling thread
942
- does not own the mutex.
943
 
944
- *Effects:* Constructs an object of type `unique_lock` and calls
945
- `m.lock()`.
946
 
947
- *Postconditions:* `pm == addressof(m)` and `owns == true`.
948
 
949
  ``` cpp
950
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
951
  ```
952
 
953
- *Effects:* Constructs an object of type `unique_lock`.
954
-
955
- *Postconditions:* `pm == addressof(m)` and `owns == false`.
956
 
957
  ``` cpp
958
  unique_lock(mutex_type& m, try_to_lock_t);
959
  ```
960
 
961
- *Requires:* The supplied `Mutex` type shall meet the `Lockable`
962
- requirements ([[thread.req.lockable.req]]). If `mutex_type` is not a
963
  recursive mutex the calling thread does not own the mutex.
964
 
965
- *Effects:* Constructs an object of type `unique_lock` and calls
966
- `m.try_lock()`.
967
 
968
- *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
969
- the value returned by the call to `m.try_lock()`.
970
 
971
  ``` cpp
972
  unique_lock(mutex_type& m, adopt_lock_t);
973
  ```
974
 
975
- *Requires:* The calling thread owns the mutex.
976
 
977
- *Effects:* Constructs an object of type `unique_lock`.
978
-
979
- *Postconditions:* `pm == addressof(m)` and `owns == true`.
980
 
981
  *Throws:* Nothing.
982
 
983
  ``` cpp
984
  template<class Clock, class Duration>
985
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
986
  ```
987
 
988
- *Requires:* If `mutex_type` is not a recursive mutex the calling thread
989
- does not own the mutex. The supplied `Mutex` type shall meet the
990
- `TimedLockable` requirements ([[thread.req.lockable.timed]]).
991
 
992
- *Effects:* Constructs an object of type `unique_lock` and calls
993
- `m.try_lock_until(abs_time)`.
994
 
995
- *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
996
- the value returned by the call to `m.try_lock_until(abs_time)`.
997
 
998
  ``` cpp
999
  template<class Rep, class Period>
1000
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
1001
  ```
1002
 
1003
- *Requires:* If `mutex_type` is not a recursive mutex the calling thread
1004
- does not own the mutex. The supplied `Mutex` type shall meet the
1005
- `TimedLockable` requirements ([[thread.req.lockable.timed]]).
1006
 
1007
- *Effects:* Constructs an object of type `unique_lock` and calls
1008
- `m.try_lock_for(rel_time)`.
1009
 
1010
- *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
1011
- the value returned by the call to `m.try_lock_for(rel_time)`.
1012
 
1013
  ``` cpp
1014
  unique_lock(unique_lock&& u) noexcept;
1015
  ```
1016
 
1017
- *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
1018
- the state of `u` just prior to this construction), `u.pm == 0` and
1019
  `u.owns == false`.
1020
 
1021
  ``` cpp
1022
  unique_lock& operator=(unique_lock&& u);
1023
  ```
1024
 
1025
  *Effects:* If `owns` calls `pm->unlock()`.
1026
 
1027
- *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
1028
- the state of `u` just prior to this construction), `u.pm == 0` and
1029
  `u.owns == false`.
1030
 
1031
  [*Note 1*: With a recursive mutex it is possible for both `*this` and
1032
  `u` to own the same mutex before the assignment. In this case, `*this`
1033
  will own the mutex after the assignment and `u` will not. — *end note*]
@@ -1038,44 +1018,44 @@ will own the mutex after the assignment and `u` will not. — *end note*]
1038
  ~unique_lock();
1039
  ```
1040
 
1041
  *Effects:* If `owns` calls `pm->unlock()`.
1042
 
1043
- ##### `unique_lock` locking <a id="thread.lock.unique.locking">[[thread.lock.unique.locking]]</a>
1044
 
1045
  ``` cpp
1046
  void lock();
1047
  ```
1048
 
1049
  *Effects:* As if by `pm->lock()`.
1050
 
1051
- *Postconditions:* `owns == true`.
1052
 
1053
  *Throws:* Any exception thrown by `pm->lock()`. `system_error` when an
1054
- exception is required ([[thread.req.exception]]).
1055
 
1056
  *Error conditions:*
1057
 
1058
  - `operation_not_permitted` — if `pm` is `nullptr`.
1059
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
1060
 
1061
  ``` cpp
1062
  bool try_lock();
1063
  ```
1064
 
1065
- *Requires:* The supplied `Mutex` shall meet the `Lockable`
1066
- requirements ([[thread.req.lockable.req]]).
1067
 
1068
  *Effects:* As if by `pm->try_lock()`.
1069
 
1070
  *Returns:* The value returned by the call to `try_lock()`.
1071
 
1072
- *Postconditions:* `owns == res`, where `res` is the value returned by
1073
- the call to `try_lock()`.
1074
 
1075
  *Throws:* Any exception thrown by `pm->try_lock()`. `system_error` when
1076
- an exception is required ([[thread.req.exception]]).
1077
 
1078
  *Error conditions:*
1079
 
1080
  - `operation_not_permitted` — if `pm` is `nullptr`.
1081
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1083,22 +1063,22 @@ an exception is required ([[thread.req.exception]]).
1083
  ``` cpp
1084
  template<class Clock, class Duration>
1085
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1086
  ```
1087
 
1088
- *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
1089
- requirements ([[thread.req.lockable.timed]]).
1090
 
1091
  *Effects:* As if by `pm->try_lock_until(abs_time)`.
1092
 
1093
  *Returns:* The value returned by the call to `try_lock_until(abs_time)`.
1094
 
1095
- *Postconditions:* `owns == res`, where `res` is the value returned by
1096
- the call to `try_lock_until(abs_time)`.
1097
 
1098
  *Throws:* Any exception thrown by `pm->try_lock_until()`. `system_error`
1099
- when an exception is required ([[thread.req.exception]]).
1100
 
1101
  *Error conditions:*
1102
 
1103
  - `operation_not_permitted` — if `pm` is `nullptr`.
1104
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1106,22 +1086,22 @@ when an exception is required ([[thread.req.exception]]).
1106
  ``` cpp
1107
  template<class Rep, class Period>
1108
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1109
  ```
1110
 
1111
- *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
1112
- requirements ([[thread.req.lockable.timed]]).
1113
 
1114
  *Effects:* As if by `pm->try_lock_for(rel_time)`.
1115
 
1116
- *Returns:* The value returned by the call to `try_lock_until(rel_time)`.
1117
 
1118
- *Postconditions:* `owns == res`, where `res` is the value returned by
1119
- the call to `try_lock_for(rel_time)`.
1120
 
1121
  *Throws:* Any exception thrown by `pm->try_lock_for()`. `system_error`
1122
- when an exception is required ([[thread.req.exception]]).
1123
 
1124
  *Error conditions:*
1125
 
1126
  - `operation_not_permitted` — if `pm` is `nullptr`.
1127
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1130,20 +1110,20 @@ when an exception is required ([[thread.req.exception]]).
1130
  void unlock();
1131
  ```
1132
 
1133
  *Effects:* As if by `pm->unlock()`.
1134
 
1135
- *Postconditions:* `owns == false`.
1136
 
1137
  *Throws:* `system_error` when an exception is
1138
- required ([[thread.req.exception]]).
1139
 
1140
  *Error conditions:*
1141
 
1142
  - `operation_not_permitted` — if on entry `owns` is `false`.
1143
 
1144
- ##### `unique_lock` modifiers <a id="thread.lock.unique.mod">[[thread.lock.unique.mod]]</a>
1145
 
1146
  ``` cpp
1147
  void swap(unique_lock& u) noexcept;
1148
  ```
1149
 
@@ -1153,20 +1133,20 @@ void swap(unique_lock& u) noexcept;
1153
  mutex_type* release() noexcept;
1154
  ```
1155
 
1156
  *Returns:* The previous value of `pm`.
1157
 
1158
- *Postconditions:* `pm == 0` and `owns == false`.
1159
 
1160
  ``` cpp
1161
  template<class Mutex>
1162
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
1163
  ```
1164
 
1165
  *Effects:* As if by `x.swap(y)`.
1166
 
1167
- ##### `unique_lock` observers <a id="thread.lock.unique.obs">[[thread.lock.unique.obs]]</a>
1168
 
1169
  ``` cpp
1170
  bool owns_lock() const noexcept;
1171
  ```
1172
 
@@ -1198,15 +1178,13 @@ namespace std {
1198
  explicit shared_lock(mutex_type& m); // blocking
1199
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
1200
  shared_lock(mutex_type& m, try_to_lock_t);
1201
  shared_lock(mutex_type& m, adopt_lock_t);
1202
  template<class Clock, class Duration>
1203
- shared_lock(mutex_type& m,
1204
- const chrono::time_point<Clock, Duration>& abs_time);
1205
  template<class Rep, class Period>
1206
- shared_lock(mutex_type& m,
1207
- const chrono::duration<Rep, Period>& rel_time);
1208
  ~shared_lock();
1209
 
1210
  shared_lock(const shared_lock&) = delete;
1211
  shared_lock& operator=(const shared_lock&) = delete;
1212
 
@@ -1234,12 +1212,10 @@ namespace std {
1234
  private:
1235
  mutex_type* pm; // exposition only
1236
  bool owns; // exposition only
1237
  };
1238
 
1239
- template<class Mutex> shared_lock(shared_lock<Mutex>) -> shared_lock<Mutex>;
1240
-
1241
  template<class Mutex>
1242
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1243
  }
1244
  ```
1245
 
@@ -1248,99 +1224,89 @@ lockable object within a scope. Shared ownership of the lockable object
1248
  may be acquired at construction or after construction, and may be
1249
  transferred, after acquisition, to another `shared_lock` object. Objects
1250
  of type `shared_lock` are not copyable but are movable. The behavior of
1251
  a program is undefined if the contained pointer `pm` is not null and the
1252
  lockable object pointed to by `pm` does not exist for the entire
1253
- remaining lifetime ([[basic.life]]) of the `shared_lock` object. The
1254
- supplied `Mutex` type shall meet the shared mutex requirements (
1255
- [[thread.sharedtimedmutex.requirements]]).
1256
 
1257
- [*Note 1*: `shared_lock<Mutex>` meets the `TimedLockable`
1258
- requirements ([[thread.req.lockable.timed]]). — *end note*]
1259
 
1260
- ##### `shared_lock` constructors, destructor, and assignment <a id="thread.lock.shared.cons">[[thread.lock.shared.cons]]</a>
1261
 
1262
  ``` cpp
1263
  shared_lock() noexcept;
1264
  ```
1265
 
1266
- *Effects:* Constructs an object of type `shared_lock`.
1267
-
1268
- *Postconditions:* `pm == nullptr` and `owns == false`.
1269
 
1270
  ``` cpp
1271
  explicit shared_lock(mutex_type& m);
1272
  ```
1273
 
1274
- *Requires:* The calling thread does not own the mutex for any ownership
1275
- mode.
1276
 
1277
- *Effects:* Constructs an object of type `shared_lock` and calls
1278
- `m.lock_shared()`.
1279
 
1280
- *Postconditions:* `pm == addressof(m)` and `owns == true`.
1281
 
1282
  ``` cpp
1283
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
1284
  ```
1285
 
1286
- *Effects:* Constructs an object of type `shared_lock`.
1287
-
1288
- *Postconditions:* `pm == addressof(m)` and `owns == false`.
1289
 
1290
  ``` cpp
1291
  shared_lock(mutex_type& m, try_to_lock_t);
1292
  ```
1293
 
1294
- *Requires:* The calling thread does not own the mutex for any ownership
1295
- mode.
1296
 
1297
- *Effects:* Constructs an object of type `shared_lock` and calls
1298
- `m.try_lock_shared()`.
1299
 
1300
- *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
1301
- the value returned by the call to `m.try_lock_shared()`.
1302
 
1303
  ``` cpp
1304
  shared_lock(mutex_type& m, adopt_lock_t);
1305
  ```
1306
 
1307
- *Requires:* The calling thread has shared ownership of the mutex.
1308
 
1309
- *Effects:* Constructs an object of type `shared_lock`.
1310
-
1311
- *Postconditions:* `pm == addressof(m)` and `owns == true`.
1312
 
1313
  ``` cpp
1314
  template<class Clock, class Duration>
1315
  shared_lock(mutex_type& m,
1316
  const chrono::time_point<Clock, Duration>& abs_time);
1317
  ```
1318
 
1319
- *Requires:* The calling thread does not own the mutex for any ownership
1320
- mode.
1321
 
1322
- *Effects:* Constructs an object of type `shared_lock` and calls
1323
- `m.try_lock_shared_until(abs_time)`.
1324
 
1325
- *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
1326
- the value returned by the call to `m.try_lock_shared_until(abs_time)`.
1327
 
1328
  ``` cpp
1329
  template<class Rep, class Period>
1330
  shared_lock(mutex_type& m,
1331
  const chrono::duration<Rep, Period>& rel_time);
1332
  ```
1333
 
1334
- *Requires:* The calling thread does not own the mutex for any ownership
1335
- mode.
1336
 
1337
- *Effects:* Constructs an object of type `shared_lock` and calls
1338
- `m.try_lock_shared_for(rel_time)`.
1339
 
1340
- *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
1341
- the value returned by the call to `m.try_lock_shared_for(rel_time)`.
1342
 
1343
  ``` cpp
1344
  ~shared_lock();
1345
  ```
1346
 
@@ -1348,36 +1314,36 @@ the value returned by the call to `m.try_lock_shared_for(rel_time)`.
1348
 
1349
  ``` cpp
1350
  shared_lock(shared_lock&& sl) noexcept;
1351
  ```
1352
 
1353
- *Postconditions:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
1354
- is the state of `sl` just prior to this construction),
1355
- `sl.pm == nullptr` and `sl.owns == false`.
1356
 
1357
  ``` cpp
1358
  shared_lock& operator=(shared_lock&& sl) noexcept;
1359
  ```
1360
 
1361
  *Effects:* If `owns` calls `pm->unlock_shared()`.
1362
 
1363
- *Postconditions:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
1364
- is the state of `sl` just prior to this assignment), `sl.pm == nullptr`
1365
- and `sl.owns == false`.
1366
 
1367
- ##### `shared_lock` locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
1368
 
1369
  ``` cpp
1370
  void lock();
1371
  ```
1372
 
1373
  *Effects:* As if by `pm->lock_shared()`.
1374
 
1375
- *Postconditions:* `owns == true`.
1376
 
1377
  *Throws:* Any exception thrown by `pm->lock_shared()`. `system_error`
1378
- when an exception is required ([[thread.req.exception]]).
1379
 
1380
  *Error conditions:*
1381
 
1382
  - `operation_not_permitted` — if `pm` is `nullptr`.
1383
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1388,39 +1354,36 @@ bool try_lock();
1388
 
1389
  *Effects:* As if by `pm->try_lock_shared()`.
1390
 
1391
  *Returns:* The value returned by the call to `pm->try_lock_shared()`.
1392
 
1393
- *Postconditions:* `owns == res`, where `res` is the value returned by
1394
- the call to `pm->try_lock_shared()`.
1395
 
1396
  *Throws:* Any exception thrown by `pm->try_lock_shared()`.
1397
- `system_error` when an exception is
1398
- required ([[thread.req.exception]]).
1399
 
1400
  *Error conditions:*
1401
 
1402
  - `operation_not_permitted` — if `pm` is `nullptr`.
1403
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
1404
 
1405
  ``` cpp
1406
  template<class Clock, class Duration>
1407
- bool
1408
- try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1409
  ```
1410
 
1411
  *Effects:* As if by `pm->try_lock_shared_until(abs_time)`.
1412
 
1413
  *Returns:* The value returned by the call to
1414
  `pm->try_lock_shared_until(abs_time)`.
1415
 
1416
- *Postconditions:* `owns == res`, where `res` is the value returned by
1417
- the call to `pm->try_lock_shared_until(abs_time)`.
1418
 
1419
  *Throws:* Any exception thrown by `pm->try_lock_shared_until(abs_time)`.
1420
- `system_error` when an exception is
1421
- required ([[thread.req.exception]]).
1422
 
1423
  *Error conditions:*
1424
 
1425
  - `operation_not_permitted` — if `pm` is `nullptr`.
1426
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1433,16 +1396,15 @@ template <class Rep, class Period>
1433
  *Effects:* As if by `pm->try_lock_shared_for(rel_time)`.
1434
 
1435
  *Returns:* The value returned by the call to
1436
  `pm->try_lock_shared_for(rel_time)`.
1437
 
1438
- *Postconditions:* `owns == res`, where `res` is the value returned by
1439
- the call to `pm->try_lock_shared_for(rel_time)`.
1440
 
1441
  *Throws:* Any exception thrown by `pm->try_lock_shared_for(rel_time)`.
1442
- `system_error` when an exception is
1443
- required ([[thread.req.exception]]).
1444
 
1445
  *Error conditions:*
1446
 
1447
  - `operation_not_permitted` — if `pm` is `nullptr`.
1448
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
@@ -1451,20 +1413,20 @@ required ([[thread.req.exception]]).
1451
  void unlock();
1452
  ```
1453
 
1454
  *Effects:* As if by `pm->unlock_shared()`.
1455
 
1456
- *Postconditions:* `owns == false`.
1457
 
1458
  *Throws:* `system_error` when an exception is
1459
- required ([[thread.req.exception]]).
1460
 
1461
  *Error conditions:*
1462
 
1463
  - `operation_not_permitted` — if on entry `owns` is `false`.
1464
 
1465
- ##### `shared_lock` modifiers <a id="thread.lock.shared.mod">[[thread.lock.shared.mod]]</a>
1466
 
1467
  ``` cpp
1468
  void swap(shared_lock& sl) noexcept;
1469
  ```
1470
 
@@ -1474,20 +1436,20 @@ void swap(shared_lock& sl) noexcept;
1474
  mutex_type* release() noexcept;
1475
  ```
1476
 
1477
  *Returns:* The previous value of `pm`.
1478
 
1479
- *Postconditions:* `pm == nullptr` and `owns == false`.
1480
 
1481
  ``` cpp
1482
  template<class Mutex>
1483
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1484
  ```
1485
 
1486
  *Effects:* As if by `x.swap(y)`.
1487
 
1488
- ##### `shared_lock` observers <a id="thread.lock.shared.obs">[[thread.lock.shared.obs]]</a>
1489
 
1490
  ``` cpp
1491
  bool owns_lock() const noexcept;
1492
  ```
1493
 
@@ -1509,48 +1471,47 @@ mutex_type* mutex() const noexcept;
1509
 
1510
  ``` cpp
1511
  template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
1512
  ```
1513
 
1514
- *Requires:* Each template parameter type shall meet the `Lockable`
1515
  requirements.
1516
 
1517
  [*Note 1*: The `unique_lock` class template meets these requirements
1518
  when suitably instantiated. — *end note*]
1519
 
1520
  *Effects:* Calls `try_lock()` for each argument in order beginning with
1521
  the first until all arguments have been processed or a call to
1522
  `try_lock()` fails, either by returning `false` or by throwing an
1523
- exception. If a call to `try_lock()` fails, `unlock()` shall be called
1524
- for all prior arguments and there shall be no further calls to
1525
- `try_lock()`.
1526
 
1527
  *Returns:* `-1` if all calls to `try_lock()` returned `true`, otherwise
1528
  a zero-based index value that indicates the argument for which
1529
  `try_lock()` returned `false`.
1530
 
1531
  ``` cpp
1532
  template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
1533
  ```
1534
 
1535
- *Requires:* Each template parameter type shall meet the `Lockable`
1536
- requirements,
1537
 
1538
  [*Note 2*: The `unique_lock` class template meets these requirements
1539
  when suitably instantiated. — *end note*]
1540
 
1541
  *Effects:* All arguments are locked via a sequence of calls to `lock()`,
1542
- `try_lock()`, or `unlock()` on each argument. The sequence of calls
1543
- shall not result in deadlock, but is otherwise unspecified.
1544
 
1545
  [*Note 3*: A deadlock avoidance algorithm such as try-and-back-off must
1546
  be used, but the specific algorithm is not specified to avoid
1547
  over-constraining implementations. — *end note*]
1548
 
1549
- If a call to `lock()` or `try_lock()` throws an exception, `unlock()`
1550
- shall be called for any argument that had been locked by a call to
1551
- `lock()` or `try_lock()`.
1552
 
1553
  ### Call once <a id="thread.once">[[thread.once]]</a>
1554
 
1555
  #### Struct `once_flag` <a id="thread.once.onceflag">[[thread.once.onceflag]]</a>
1556
 
@@ -1570,57 +1531,49 @@ to initialize data without causing a data race or deadlock.
1570
 
1571
  ``` cpp
1572
  constexpr once_flag() noexcept;
1573
  ```
1574
 
1575
- *Effects:* Constructs an object of type `once_flag`.
1576
-
1577
  *Synchronization:* The construction of a `once_flag` object is not
1578
  synchronized.
1579
 
1580
- *Postconditions:* The object’s internal state is set to indicate to an
1581
  invocation of `call_once` with the object as its initial argument that
1582
  no function has been called.
1583
 
1584
  #### Function `call_once` <a id="thread.once.callonce">[[thread.once.callonce]]</a>
1585
 
1586
  ``` cpp
1587
  template<class Callable, class... Args>
1588
  void call_once(once_flag& flag, Callable&& func, Args&&... args);
1589
  ```
1590
 
1591
- *Requires:*
1592
-
1593
- ``` cpp
1594
- INVOKE(std::forward<Callable>(func), std::forward<Args>(args)...)
1595
- ```
1596
-
1597
- (see [[func.require]]) shall be a valid expression.
1598
 
1599
  *Effects:* An execution of `call_once` that does not call its `func` is
1600
  a *passive* execution. An execution of `call_once` that calls its `func`
1601
- is an *active* execution. An active execution shall call *INVOKE*(
1602
  std::forward\<Callable\>(func), std::forward\<Args\>(args)...). If such
1603
  a call to `func` throws an exception the execution is *exceptional*,
1604
- otherwise it is *returning*. An exceptional execution shall propagate
1605
- the exception to the caller of `call_once`. Among all executions of
1606
- `call_once` for any given `once_flag`: at most one shall be a returning
1607
- execution; if there is a returning execution, it shall be the last
1608
- active execution; and there are passive executions only if there is a
1609
- returning execution.
1610
 
1611
  [*Note 1*: Passive executions allow other threads to reliably observe
1612
  the results produced by the earlier returning execution. — *end note*]
1613
 
1614
  *Synchronization:* For any given `once_flag`: all active executions
1615
  occur in a total order; completion of an active execution synchronizes
1616
- with ([[intro.multithread]]) the start of the next one in this total
1617
  order; and the returning execution synchronizes with the return from all
1618
  passive executions.
1619
 
1620
  *Throws:* `system_error` when an exception is
1621
- required ([[thread.req.exception]]), or any exception thrown by `func`.
1622
 
1623
  [*Example 1*:
1624
 
1625
  ``` cpp
1626
  // global flag, regular function
 
1
  ## Mutual exclusion <a id="thread.mutex">[[thread.mutex]]</a>
2
 
3
+ This subclause provides mechanisms for mutual exclusion: mutexes, locks,
4
  and call once. These mechanisms ease the production of race-free
5
+ programs [[intro.multithread]].
6
 
7
  ### Header `<mutex>` synopsis <a id="mutex.syn">[[mutex.syn]]</a>
8
 
9
  ``` cpp
10
  namespace std {
 
36
  template<class Callable, class... Args>
37
  void call_once(once_flag& flag, Callable&& func, Args&&... args);
38
  }
39
  ```
40
 
41
+ ### Header `<shared_mutex>` synopsis <a id="shared.mutex.syn">[[shared.mutex.syn]]</a>
42
 
43
  ``` cpp
44
  namespace std {
45
  class shared_mutex;
46
  class shared_timed_mutex;
 
53
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
54
 
55
  #### In general <a id="thread.mutex.requirements.general">[[thread.mutex.requirements.general]]</a>
56
 
57
  A mutex object facilitates protection against data races and allows safe
58
+ synchronization of data between execution agents
59
+ [[thread.req.lockable]]. An execution agent *owns* a mutex from the time
60
+ it successfully calls one of the lock functions until it calls unlock.
61
+ Mutexes can be either recursive or non-recursive, and can grant
62
  simultaneous ownership to one or many execution agents. Both recursive
63
  and non-recursive mutexes are supplied.
64
 
65
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
66
 
67
  The *mutex types* are the standard library types `mutex`,
68
  `recursive_mutex`, `timed_mutex`, `recursive_timed_mutex`,
69
+ `shared_mutex`, and `shared_timed_mutex`. They meet the requirements set
70
+ out in this subclause. In this description, `m` denotes an object of a
71
+ mutex type.
72
 
73
+ The mutex types meet the *Cpp17Lockable* requirements
74
+ [[thread.req.lockable.req]].
75
 
76
+ The mutex types meet *Cpp17DefaultConstructible* and
77
+ *Cpp17Destructible*. If initialization of an object of a mutex type
78
+ fails, an exception of type `system_error` is thrown. The mutex types
79
+ are neither copyable nor movable.
80
 
81
  The error conditions for error codes, if any, reported by member
82
+ functions of the mutex types are as follows:
83
 
84
  - `resource_unavailable_try_again` — if any native handle type
85
  manipulated is not available.
86
  - `operation_not_permitted` — if the thread does not have the privilege
87
  to perform the operation.
88
  - `invalid_argument` — if any native handle type manipulated as part of
89
  mutex construction is incorrect.
90
 
91
+ The implementation provides lock and unlock operations, as described
92
+ below. For purposes of determining the existence of a data race, these
93
+ behave as atomic operations [[intro.multithread]]. The lock and unlock
94
+ operations on a single mutex appears to occur in a single total order.
 
95
 
96
+ [*Note 1*: This can be viewed as the modification order
97
+ [[intro.multithread]] of the mutex. — *end note*]
98
 
99
  [*Note 2*: Construction and destruction of an object of a mutex type
100
  need not be thread-safe; other synchronization should be used to ensure
101
  that mutex objects are initialized and visible to other
102
  threads. — *end note*]
103
 
104
+ The expression `m.lock()` is well-formed and has the following
105
  semantics:
106
 
107
+ *Preconditions:* If `m` is of type `mutex`, `timed_mutex`,
108
+ `shared_mutex`, or `shared_timed_mutex`, the calling thread does not own
109
+ the mutex.
110
 
111
  *Effects:* Blocks the calling thread until ownership of the mutex can be
112
  obtained for the calling thread.
113
 
114
+ *Ensures:* The calling thread owns the mutex.
115
 
116
  *Return type:* `void`.
117
 
118
+ *Synchronization:* Prior `unlock()` operations on the same object
119
+ *synchronize with*[[intro.multithread]] this operation.
120
 
121
  *Throws:* `system_error` when an exception is
122
+ required [[thread.req.exception]].
123
 
124
  *Error conditions:*
125
 
126
  - `operation_not_permitted` — if the thread does not have the privilege
127
  to perform the operation.
128
  - `resource_deadlock_would_occur` — if the implementation detects that a
129
  deadlock would occur.
130
 
131
+ The expression `m.try_lock()` is well-formed and has the following
132
+ semantics:
133
 
134
+ *Preconditions:* If `m` is of type `mutex`, `timed_mutex`,
135
+ `shared_mutex`, or `shared_timed_mutex`, the calling thread does not own
136
+ the mutex.
137
 
138
  *Effects:* Attempts to obtain ownership of the mutex for the calling
139
  thread without blocking. If ownership is not obtained, there is no
140
  effect and `try_lock()` immediately returns. An implementation may fail
141
  to obtain the lock even if it is not held by any other thread.
142
 
143
  [*Note 1*: This spurious failure is normally uncommon, but allows
144
+ interesting implementations based on a simple compare and
145
+ exchange [[atomics]]. — *end note*]
146
 
147
  An implementation should ensure that `try_lock()` does not consistently
148
  return `false` in the absence of contending mutex acquisitions.
149
 
150
  *Return type:* `bool`.
151
 
152
  *Returns:* `true` if ownership of the mutex was obtained for the calling
153
  thread, otherwise `false`.
154
 
155
  *Synchronization:* If `try_lock()` returns `true`, prior `unlock()`
156
+ operations on the same object *synchronize with*[[intro.multithread]]
157
+ this operation.
158
 
159
  [*Note 2*: Since `lock()` does not synchronize with a failed subsequent
160
  `try_lock()`, the visibility rules are weak enough that little would be
161
  known about the state after a failure, even in the absence of spurious
162
  failures. — *end note*]
163
 
164
  *Throws:* Nothing.
165
 
166
+ The expression `m.unlock()` is well-formed and has the following
167
  semantics:
168
 
169
+ *Preconditions:* The calling thread owns the mutex.
170
 
171
  *Effects:* Releases the calling thread’s ownership of the mutex.
172
 
173
  *Return type:* `void`.
174
 
175
  *Synchronization:* This operation synchronizes
176
+ with [[intro.multithread]] subsequent lock operations that obtain
177
  ownership on the same object.
178
 
179
  *Throws:* Nothing.
180
 
181
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
 
192
 
193
  void lock();
194
  bool try_lock();
195
  void unlock();
196
 
197
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
198
+ native_handle_type native_handle(); // see~[thread.req.native]
199
  };
200
  }
201
  ```
202
 
203
  The class `mutex` provides a non-recursive mutex with exclusive
 
213
  required to handle such scenarios correctly, as long as thread `A`
214
  doesn’t access the mutex after the unlock call returns. These cases
215
  typically occur when a reference-counted object contains a mutex that is
216
  used to protect the reference count. — *end note*]
217
 
218
+ The class `mutex` meets all of the mutex requirements
219
+ [[thread.mutex.requirements]]. It is a standard-layout class
220
+ [[class.prop]].
221
 
222
+ [*Note 4*: A program can deadlock if the thread that owns a `mutex`
223
  object calls `lock()` on that object. If the implementation can detect
224
+ the deadlock, a `resource_deadlock_would_occur` error condition might be
225
  observed. — *end note*]
226
 
227
  The behavior of a program is undefined if it destroys a `mutex` object
228
  owned by any thread or a thread terminates while owning a `mutex`
229
  object.
 
242
 
243
  void lock();
244
  bool try_lock() noexcept;
245
  void unlock();
246
 
247
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
248
+ native_handle_type native_handle(); // see~[thread.req.native]
249
  };
250
  }
251
  ```
252
 
253
  The class `recursive_mutex` provides a recursive mutex with exclusive
254
  ownership semantics. If one thread owns a `recursive_mutex` object,
255
  attempts by another thread to acquire ownership of that object will fail
256
  (for `try_lock()`) or block (for `lock()`) until the first thread has
257
  completely released ownership.
258
 
259
+ The class `recursive_mutex` meets all of the mutex requirements
260
+ [[thread.mutex.requirements]]. It is a standard-layout class
261
+ [[class.prop]].
262
 
263
  A thread that owns a `recursive_mutex` object may acquire additional
264
  levels of ownership by calling `lock()` or `try_lock()` on that object.
265
  It is unspecified how many levels of ownership may be acquired by a
266
  single thread. If a thread has already acquired the maximum level of
267
  ownership for a `recursive_mutex` object, additional calls to
268
+ `try_lock()` fail, and additional calls to `lock()` throw an exception
269
+ of type `system_error`. A thread shall call `unlock()` once for each
270
+ level of ownership acquired by calls to `lock()` and `try_lock()`. Only
271
+ when all levels of ownership have been released may ownership be
272
+ acquired by another thread.
273
 
274
  The behavior of a program is undefined if:
275
 
276
  - it destroys a `recursive_mutex` object owned by any thread or
277
  - a thread terminates while owning a `recursive_mutex` object.
278
 
279
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
280
 
281
  The *timed mutex types* are the standard library types `timed_mutex`,
282
+ `recursive_timed_mutex`, and `shared_timed_mutex`. They meet the
283
  requirements set out below. In this description, `m` denotes an object
284
  of a mutex type, `rel_time` denotes an object of an instantiation of
285
+ `duration` [[time.duration]], and `abs_time` denotes an object of an
286
+ instantiation of `time_point` [[time.point]].
287
 
288
+ The timed mutex types meet the *Cpp17TimedLockable* requirements
289
+ [[thread.req.lockable.timed]].
290
 
291
+ The expression `m.try_lock_for(rel_time)` is well-formed and has the
292
+ following semantics:
293
 
294
+ *Preconditions:* If `m` is of type `timed_mutex` or
295
+ `shared_timed_mutex`, the calling thread does not own the mutex.
296
 
297
  *Effects:* The function attempts to obtain ownership of the mutex within
298
+ the relative timeout [[thread.req.timing]] specified by `rel_time`. If
299
+ the time specified by `rel_time` is less than or equal to
300
  `rel_time.zero()`, the function attempts to obtain ownership without
301
+ blocking (as if by calling `try_lock()`). The function returns within
302
+ the timeout specified by `rel_time` only if it has obtained ownership of
303
+ the mutex object.
304
 
305
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
306
  will be obtained if the lock is available, but implementations are
307
  expected to make a strong effort to do so. — *end note*]
308
 
309
  *Return type:* `bool`.
310
 
311
  *Returns:* `true` if ownership was obtained, otherwise `false`.
312
 
313
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
314
+ operations on the same object *synchronize with*[[intro.multithread]]
315
+ this operation.
316
 
317
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
318
 
319
+ The expression `m.try_lock_until(abs_time)` is well-formed and has the
320
+ following semantics:
321
 
322
+ *Preconditions:* If `m` is of type `timed_mutex` or
323
+ `shared_timed_mutex`, the calling thread does not own the mutex.
324
 
325
  *Effects:* The function attempts to obtain ownership of the mutex. If
326
  `abs_time` has already passed, the function attempts to obtain ownership
327
+ without blocking (as if by calling `try_lock()`). The function returns
328
+ before the absolute timeout [[thread.req.timing]] specified by
329
  `abs_time` only if it has obtained ownership of the mutex object.
330
 
331
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
332
  will be obtained if the lock is available, but implementations are
333
  expected to make a strong effort to do so. — *end note*]
 
336
 
337
  *Returns:* `true` if ownership was obtained, otherwise `false`.
338
 
339
  *Synchronization:* If `try_lock_until()` returns `true`, prior
340
  `unlock()` operations on the same object *synchronize
341
+ with*[[intro.multithread]] this operation.
342
 
343
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
344
 
345
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
346
 
347
  ``` cpp
348
  namespace std {
 
360
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
361
  template<class Clock, class Duration>
362
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
363
  void unlock();
364
 
365
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
366
+ native_handle_type native_handle(); // see~[thread.req.native]
367
  };
368
  }
369
  ```
370
 
371
  The class `timed_mutex` provides a non-recursive mutex with exclusive
 
374
  `try_lock()`) or block (for `lock()`, `try_lock_for()`, and
375
  `try_lock_until()`) until the owning thread has released ownership with
376
  a call to `unlock()` or the call to `try_lock_for()` or
377
  `try_lock_until()` times out (having failed to obtain ownership).
378
 
379
+ The class `timed_mutex` meets all of the timed mutex requirements
380
+ [[thread.timedmutex.requirements]]. It is a standard-layout class
381
+ [[class.prop]].
382
 
383
  The behavior of a program is undefined if:
384
 
385
  - it destroys a `timed_mutex` object owned by any thread,
386
  - a thread that owns a `timed_mutex` object calls `lock()`,
 
406
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
407
  template<class Clock, class Duration>
408
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
409
  void unlock();
410
 
411
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
412
+ native_handle_type native_handle(); // see~[thread.req.native]
413
  };
414
  }
415
  ```
416
 
417
  The class `recursive_timed_mutex` provides a recursive mutex with
 
420
  ownership of that object will fail (for `try_lock()`) or block (for
421
  `lock()`, `try_lock_for()`, and `try_lock_until()`) until the owning
422
  thread has completely released ownership or the call to `try_lock_for()`
423
  or `try_lock_until()` times out (having failed to obtain ownership).
424
 
425
+ The class `recursive_timed_mutex` meets all of the timed mutex
426
+ requirements [[thread.timedmutex.requirements]]. It is a standard-layout
427
+ class [[class.prop]].
428
 
429
  A thread that owns a `recursive_timed_mutex` object may acquire
430
  additional levels of ownership by calling `lock()`, `try_lock()`,
431
  `try_lock_for()`, or `try_lock_until()` on that object. It is
432
  unspecified how many levels of ownership may be acquired by a single
433
  thread. If a thread has already acquired the maximum level of ownership
434
  for a `recursive_timed_mutex` object, additional calls to `try_lock()`,
435
+ `try_lock_for()`, or `try_lock_until()` fail, and additional calls to
436
+ `lock()` throw an exception of type `system_error`. A thread shall call
437
+ `unlock()` once for each level of ownership acquired by calls to
438
+ `lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`. Only
439
+ when all levels of ownership have been released may ownership of the
440
+ object be acquired by another thread.
441
 
442
  The behavior of a program is undefined if:
443
 
444
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
445
  - a thread terminates while owning a `recursive_timed_mutex` object.
446
 
447
  #### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
448
 
449
  The standard library types `shared_mutex` and `shared_timed_mutex` are
450
+ *shared mutex types*. Shared mutex types meet the requirements of mutex
451
+ types [[thread.mutex.requirements.mutex]] and additionally meet the
452
+ requirements set out below. In this description, `m` denotes an object
453
+ of a shared mutex type.
454
 
455
  In addition to the exclusive lock ownership mode specified in 
456
  [[thread.mutex.requirements.mutex]], shared mutex types provide a
457
  *shared lock* ownership mode. Multiple execution agents can
458
  simultaneously hold a shared lock ownership of a shared mutex type. But
459
+ no execution agent holds a shared lock while another execution agent
460
+ holds an exclusive lock on the same shared mutex type, and vice-versa.
461
+ The maximum number of execution agents which can share a shared lock on
462
+ a single shared mutex type is unspecified, but is at least 10000. If
463
+ more than the maximum number of execution agents attempt to obtain a
464
+ shared lock, the excess execution agents block until the number of
465
+ shared locks are reduced below the maximum amount by other execution
466
+ agents releasing their shared lock.
467
 
468
+ The expression `m.lock_shared()` is well-formed and has the following
469
+ semantics:
470
 
471
+ *Preconditions:* The calling thread has no ownership of the mutex.
472
 
473
  *Effects:* Blocks the calling thread until shared ownership of the mutex
474
  can be obtained for the calling thread. If an exception is thrown then a
475
+ shared lock has not been acquired for the current thread.
476
 
477
+ *Ensures:* The calling thread has a shared lock on the mutex.
478
 
479
  *Return type:* `void`.
480
 
481
+ *Synchronization:* Prior `unlock()` operations on the same object
482
+ synchronize with [[intro.multithread]] this operation.
483
 
484
  *Throws:* `system_error` when an exception is
485
+ required [[thread.req.exception]].
486
 
487
  *Error conditions:*
488
 
489
  - `operation_not_permitted` — if the thread does not have the privilege
490
  to perform the operation.
491
  - `resource_deadlock_would_occur` — if the implementation detects that a
492
  deadlock would occur.
493
 
494
+ The expression `m.unlock_shared()` is well-formed and has the following
495
+ semantics:
496
 
497
+ *Preconditions:* The calling thread holds a shared lock on the mutex.
498
 
499
  *Effects:* Releases a shared lock on the mutex held by the calling
500
  thread.
501
 
502
  *Return type:* `void`.
503
 
504
  *Synchronization:* This operation synchronizes
505
+ with [[intro.multithread]] subsequent `lock()` operations that obtain
506
  ownership on the same object.
507
 
508
  *Throws:* Nothing.
509
 
510
+ The expression `m.try_lock_shared()` is well-formed and has the
511
  following semantics:
512
 
513
+ *Preconditions:* The calling thread has no ownership of the mutex.
514
 
515
  *Effects:* Attempts to obtain shared ownership of the mutex for the
516
  calling thread without blocking. If shared ownership is not obtained,
517
  there is no effect and `try_lock_shared()` immediately returns. An
518
  implementation may fail to obtain the lock even if it is not held by any
 
523
  *Returns:* `true` if the shared ownership lock was acquired, `false`
524
  otherwise.
525
 
526
  *Synchronization:* If `try_lock_shared()` returns `true`, prior
527
  `unlock()` operations on the same object synchronize
528
+ with [[intro.multithread]] this operation.
529
 
530
  *Throws:* Nothing.
531
 
532
+ ##### Class `shared_mutex` <a id="thread.sharedmutex.class">[[thread.sharedmutex.class]]</a>
533
 
534
  ``` cpp
535
  namespace std {
536
  class shared_mutex {
537
  public:
 
539
  ~shared_mutex();
540
 
541
  shared_mutex(const shared_mutex&) = delete;
542
  shared_mutex& operator=(const shared_mutex&) = delete;
543
 
544
+ // exclusive ownership
545
  void lock(); // blocking
546
  bool try_lock();
547
  void unlock();
548
 
549
+ // shared ownership
550
  void lock_shared(); // blocking
551
  bool try_lock_shared();
552
  void unlock_shared();
553
 
554
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
555
+ native_handle_type native_handle(); // see~[thread.req.native]
556
  };
557
  }
558
  ```
559
 
560
  The class `shared_mutex` provides a non-recursive mutex with shared
561
  ownership semantics.
562
 
563
+ The class `shared_mutex` meets all of the shared mutex requirements
564
+ [[thread.sharedmutex.requirements]]. It is a standard-layout class
565
+ [[class.prop]].
566
 
567
  The behavior of a program is undefined if:
568
 
569
  - it destroys a `shared_mutex` object owned by any thread,
570
  - a thread attempts to recursively gain any ownership of a
 
575
  `shared_mutex` may be a synonym for `shared_timed_mutex`.
576
 
577
  #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
578
 
579
  The standard library type `shared_timed_mutex` is a *shared timed mutex
580
+ type*. Shared timed mutex types meet the requirements of timed mutex
581
+ types [[thread.timedmutex.requirements]], shared mutex types
582
+ [[thread.sharedmutex.requirements]], and additionally meet the
583
  requirements set out below. In this description, `m` denotes an object
584
  of a shared timed mutex type, `rel_type` denotes an object of an
585
+ instantiation of `duration` [[time.duration]], and `abs_time` denotes an
586
+ object of an instantiation of `time_point` [[time.point]].
587
 
588
+ The expression `m.try_lock_shared_for(rel_time)` is well-formed and has
589
+ the following semantics:
590
 
591
+ *Preconditions:* The calling thread has no ownership of the mutex.
592
 
593
  *Effects:* Attempts to obtain shared lock ownership for the calling
594
+ thread within the relative timeout [[thread.req.timing]] specified by
595
  `rel_time`. If the time specified by `rel_time` is less than or equal to
596
  `rel_time.zero()`, the function attempts to obtain ownership without
597
+ blocking (as if by calling `try_lock_shared()`). The function returns
598
+ within the timeout specified by `rel_time` only if it has obtained
599
+ shared ownership of the mutex object.
600
 
601
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
602
  will be obtained if the lock is available, but implementations are
603
  expected to make a strong effort to do so. — *end note*]
604
 
605
+ If an exception is thrown then a shared lock has not been acquired for
606
+ the current thread.
607
 
608
  *Return type:* `bool`.
609
 
610
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
611
 
612
  *Synchronization:* If `try_lock_shared_for()` returns `true`, prior
613
  `unlock()` operations on the same object synchronize
614
+ with [[intro.multithread]] this operation.
615
 
616
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
617
 
618
+ The expression `m.try_lock_shared_until(abs_time)` is well-formed and
619
+ has the following semantics:
620
 
621
+ *Preconditions:* The calling thread has no ownership of the mutex.
622
 
623
  *Effects:* The function attempts to obtain shared ownership of the
624
  mutex. If `abs_time` has already passed, the function attempts to obtain
625
  shared ownership without blocking (as if by calling
626
+ `try_lock_shared()`). The function returns before the absolute
627
+ timeout [[thread.req.timing]] specified by `abs_time` only if it has
628
  obtained shared ownership of the mutex object.
629
 
630
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
631
  will be obtained if the lock is available, but implementations are
632
  expected to make a strong effort to do so. — *end note*]
633
 
634
+ If an exception is thrown then a shared lock has not been acquired for
635
+ the current thread.
636
 
637
  *Return type:* `bool`.
638
 
639
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
640
 
641
  *Synchronization:* If `try_lock_shared_until()` returns `true`, prior
642
  `unlock()` operations on the same object synchronize
643
+ with [[intro.multithread]] this operation.
644
 
645
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
646
 
647
  ##### Class `shared_timed_mutex` <a id="thread.sharedtimedmutex.class">[[thread.sharedtimedmutex.class]]</a>
648
 
649
  ``` cpp
650
  namespace std {
 
654
  ~shared_timed_mutex();
655
 
656
  shared_timed_mutex(const shared_timed_mutex&) = delete;
657
  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
658
 
659
+ // exclusive ownership
660
  void lock(); // blocking
661
  bool try_lock();
662
  template<class Rep, class Period>
663
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
664
  template<class Clock, class Duration>
665
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
666
  void unlock();
667
 
668
+ // shared ownership
669
  void lock_shared(); // blocking
670
  bool try_lock_shared();
671
  template<class Rep, class Period>
672
+ bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
 
673
  template<class Clock, class Duration>
674
+ bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
 
675
  void unlock_shared();
676
  };
677
  }
678
  ```
679
 
680
  The class `shared_timed_mutex` provides a non-recursive mutex with
681
  shared ownership semantics.
682
 
683
+ The class `shared_timed_mutex` meets all of the shared timed mutex
684
+ requirements [[thread.sharedtimedmutex.requirements]]. It is a
685
+ standard-layout class [[class.prop]].
686
 
687
  The behavior of a program is undefined if:
688
 
689
  - it destroys a `shared_timed_mutex` object owned by any thread,
690
  - a thread attempts to recursively gain any ownership of a
 
740
  lock_guard& operator=(const lock_guard&) = delete;
741
 
742
  private:
743
  mutex_type& pm; // exposition only
744
  };
 
 
745
  }
746
  ```
747
 
748
  An object of type `lock_guard` controls the ownership of a lockable
749
  object within a scope. A `lock_guard` object maintains ownership of a
750
+ lockable object throughout the `lock_guard` object’s lifetime
751
+ [[basic.life]]. The behavior of a program is undefined if the lockable
752
  object referenced by `pm` does not exist for the entire lifetime of the
753
  `lock_guard` object. The supplied `Mutex` type shall meet the
754
+ *Cpp17BasicLockable* requirements [[thread.req.lockable.basic]].
755
 
756
  ``` cpp
757
  explicit lock_guard(mutex_type& m);
758
  ```
759
 
760
+ *Preconditions:* If `mutex_type` is not a recursive mutex, the calling
761
+ thread does not own the mutex `m`.
762
 
763
+ *Effects:* Initializes `pm` with `m`. Calls `m.lock()`.
 
 
764
 
765
  ``` cpp
766
  lock_guard(mutex_type& m, adopt_lock_t);
767
  ```
768
 
769
+ *Preconditions:* The calling thread owns the mutex `m`.
770
 
771
+ *Effects:* Initializes `pm` with `m`.
772
 
773
  *Throws:* Nothing.
774
 
775
  ``` cpp
776
  ~lock_guard();
 
786
  class scoped_lock {
787
  public:
788
  using mutex_type = Mutex; // If MutexTypes... consists of the single type Mutex
789
 
790
  explicit scoped_lock(MutexTypes&... m);
791
+ explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
792
  ~scoped_lock();
793
 
794
  scoped_lock(const scoped_lock&) = delete;
795
  scoped_lock& operator=(const scoped_lock&) = delete;
796
 
797
  private:
798
  tuple<MutexTypes&...> pm; // exposition only
799
  };
 
 
 
800
  }
801
  ```
802
 
803
  An object of type `scoped_lock` controls the ownership of lockable
804
  objects within a scope. A `scoped_lock` object maintains ownership of
805
+ lockable objects throughout the `scoped_lock` object’s lifetime
806
+ [[basic.life]]. The behavior of a program is undefined if the lockable
807
  objects referenced by `pm` do not exist for the entire lifetime of the
808
  `scoped_lock` object. When `sizeof...(MutexTypes)` is `1`, the supplied
809
+ `Mutex` type shall meet the *Cpp17BasicLockable* requirements
810
+ [[thread.req.lockable.basic]]. Otherwise, each of the mutex types shall
811
+ meet the *Cpp17Lockable* requirements [[thread.req.lockable.req]].
812
 
813
  ``` cpp
814
  explicit scoped_lock(MutexTypes&... m);
815
  ```
816
 
817
+ *Preconditions:* If a `MutexTypes` type is not a recursive mutex, the
818
+ calling thread does not own the corresponding mutex element of `m`.
819
 
820
  *Effects:* Initializes `pm` with `tie(m...)`. Then if
821
  `sizeof...(MutexTypes)` is `0`, no effects. Otherwise if
822
  `sizeof...(MutexTypes)` is `1`, then `m.lock()`. Otherwise,
823
  `lock(m...)`.
824
 
825
  ``` cpp
826
+ explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
827
  ```
828
 
829
+ *Preconditions:* The calling thread owns all the mutexes in `m`.
830
 
831
  *Effects:* Initializes `pm` with `tie(m...)`.
832
 
833
  *Throws:* Nothing.
834
 
 
889
  private:
890
  mutex_type* pm; // exposition only
891
  bool owns; // exposition only
892
  };
893
 
 
 
894
  template<class Mutex>
895
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
896
  }
897
  ```
898
 
 
901
  at construction or after construction, and may be transferred, after
902
  acquisition, to another `unique_lock` object. Objects of type
903
  `unique_lock` are not copyable but are movable. The behavior of a
904
  program is undefined if the contained pointer `pm` is not null and the
905
  lockable object pointed to by `pm` does not exist for the entire
906
+ remaining lifetime [[basic.life]] of the `unique_lock` object. The
907
+ supplied `Mutex` type shall meet the *Cpp17BasicLockable* requirements
908
+ [[thread.req.lockable.basic]].
909
 
910
+ [*Note 1*: `unique_lock<Mutex>` meets the *Cpp17BasicLockable*
911
+ requirements. If `Mutex` meets the *Cpp17Lockable* requirements
912
+ [[thread.req.lockable.req]], `unique_lock<Mutex>` also meets the
913
+ *Cpp17Lockable* requirements; if `Mutex` meets the *Cpp17TimedLockable*
914
+ requirements [[thread.req.lockable.timed]], `unique_lock<Mutex>` also
915
+ meets the *Cpp17TimedLockable* requirements. — *end note*]
916
 
917
+ ##### Constructors, destructor, and assignment <a id="thread.lock.unique.cons">[[thread.lock.unique.cons]]</a>
918
 
919
  ``` cpp
920
  unique_lock() noexcept;
921
  ```
922
 
923
+ *Ensures:* `pm == 0` and `owns == false`.
 
 
924
 
925
  ``` cpp
926
  explicit unique_lock(mutex_type& m);
927
  ```
928
 
929
+ *Preconditions:* If `mutex_type` is not a recursive mutex the calling
930
+ thread does not own the mutex.
931
 
932
+ *Effects:* Calls `m.lock()`.
 
933
 
934
+ *Ensures:* `pm == addressof(m)` and `owns == true`.
935
 
936
  ``` cpp
937
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
938
  ```
939
 
940
+ *Ensures:* `pm == addressof(m)` and `owns == false`.
 
 
941
 
942
  ``` cpp
943
  unique_lock(mutex_type& m, try_to_lock_t);
944
  ```
945
 
946
+ *Preconditions:* The supplied `Mutex` type meets the *Cpp17Lockable*
947
+ requirements [[thread.req.lockable.req]]. If `mutex_type` is not a
948
  recursive mutex the calling thread does not own the mutex.
949
 
950
+ *Effects:* Calls `m.try_lock()`.
 
951
 
952
+ *Ensures:* `pm == addressof(m)` and `owns == res`, where `res` is the
953
+ value returned by the call to `m.try_lock()`.
954
 
955
  ``` cpp
956
  unique_lock(mutex_type& m, adopt_lock_t);
957
  ```
958
 
959
+ *Preconditions:* The calling thread owns the mutex.
960
 
961
+ *Ensures:* `pm == addressof(m)` and `owns == true`.
 
 
962
 
963
  *Throws:* Nothing.
964
 
965
  ``` cpp
966
  template<class Clock, class Duration>
967
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
968
  ```
969
 
970
+ *Preconditions:* If `mutex_type` is not a recursive mutex the calling
971
+ thread does not own the mutex. The supplied `Mutex` type meets the
972
+ *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]].
973
 
974
+ *Effects:* Calls `m.try_lock_until(abs_time)`.
 
975
 
976
+ *Ensures:* `pm == addressof(m)` and `owns == res`, where `res` is the
977
+ value returned by the call to `m.try_lock_until(abs_time)`.
978
 
979
  ``` cpp
980
  template<class Rep, class Period>
981
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
982
  ```
983
 
984
+ *Preconditions:* If `mutex_type` is not a recursive mutex the calling
985
+ thread does not own the mutex. The supplied `Mutex` type meets the
986
+ *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]].
987
 
988
+ *Effects:* Calls `m.try_lock_for(rel_time)`.
 
989
 
990
+ *Ensures:* `pm == addressof(m)` and `owns == res`, where `res` is the
991
+ value returned by the call to `m.try_lock_for(rel_time)`.
992
 
993
  ``` cpp
994
  unique_lock(unique_lock&& u) noexcept;
995
  ```
996
 
997
+ *Ensures:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is the
998
+ state of `u` just prior to this construction), `u.pm == 0` and
999
  `u.owns == false`.
1000
 
1001
  ``` cpp
1002
  unique_lock& operator=(unique_lock&& u);
1003
  ```
1004
 
1005
  *Effects:* If `owns` calls `pm->unlock()`.
1006
 
1007
+ *Ensures:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is the
1008
+ state of `u` just prior to this construction), `u.pm == 0` and
1009
  `u.owns == false`.
1010
 
1011
  [*Note 1*: With a recursive mutex it is possible for both `*this` and
1012
  `u` to own the same mutex before the assignment. In this case, `*this`
1013
  will own the mutex after the assignment and `u` will not. — *end note*]
 
1018
  ~unique_lock();
1019
  ```
1020
 
1021
  *Effects:* If `owns` calls `pm->unlock()`.
1022
 
1023
+ ##### Locking <a id="thread.lock.unique.locking">[[thread.lock.unique.locking]]</a>
1024
 
1025
  ``` cpp
1026
  void lock();
1027
  ```
1028
 
1029
  *Effects:* As if by `pm->lock()`.
1030
 
1031
+ *Ensures:* `owns == true`.
1032
 
1033
  *Throws:* Any exception thrown by `pm->lock()`. `system_error` when an
1034
+ exception is required [[thread.req.exception]].
1035
 
1036
  *Error conditions:*
1037
 
1038
  - `operation_not_permitted` — if `pm` is `nullptr`.
1039
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
1040
 
1041
  ``` cpp
1042
  bool try_lock();
1043
  ```
1044
 
1045
+ *Preconditions:* The supplied `Mutex` meets the *Cpp17Lockable*
1046
+ requirements [[thread.req.lockable.req]].
1047
 
1048
  *Effects:* As if by `pm->try_lock()`.
1049
 
1050
  *Returns:* The value returned by the call to `try_lock()`.
1051
 
1052
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1053
+ to `try_lock()`.
1054
 
1055
  *Throws:* Any exception thrown by `pm->try_lock()`. `system_error` when
1056
+ an exception is required [[thread.req.exception]].
1057
 
1058
  *Error conditions:*
1059
 
1060
  - `operation_not_permitted` — if `pm` is `nullptr`.
1061
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1063
  ``` cpp
1064
  template<class Clock, class Duration>
1065
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1066
  ```
1067
 
1068
+ *Preconditions:* The supplied `Mutex` type meets the
1069
+ *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]].
1070
 
1071
  *Effects:* As if by `pm->try_lock_until(abs_time)`.
1072
 
1073
  *Returns:* The value returned by the call to `try_lock_until(abs_time)`.
1074
 
1075
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1076
+ to `try_lock_until(abs_time)`.
1077
 
1078
  *Throws:* Any exception thrown by `pm->try_lock_until()`. `system_error`
1079
+ when an exception is required [[thread.req.exception]].
1080
 
1081
  *Error conditions:*
1082
 
1083
  - `operation_not_permitted` — if `pm` is `nullptr`.
1084
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1086
  ``` cpp
1087
  template<class Rep, class Period>
1088
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1089
  ```
1090
 
1091
+ *Preconditions:* The supplied `Mutex` type meets the
1092
+ *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]].
1093
 
1094
  *Effects:* As if by `pm->try_lock_for(rel_time)`.
1095
 
1096
+ *Returns:* The value returned by the call to `try_lock_for(rel_time)`.
1097
 
1098
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1099
+ to `try_lock_for(rel_time)`.
1100
 
1101
  *Throws:* Any exception thrown by `pm->try_lock_for()`. `system_error`
1102
+ when an exception is required [[thread.req.exception]].
1103
 
1104
  *Error conditions:*
1105
 
1106
  - `operation_not_permitted` — if `pm` is `nullptr`.
1107
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1110
  void unlock();
1111
  ```
1112
 
1113
  *Effects:* As if by `pm->unlock()`.
1114
 
1115
+ *Ensures:* `owns == false`.
1116
 
1117
  *Throws:* `system_error` when an exception is
1118
+ required [[thread.req.exception]].
1119
 
1120
  *Error conditions:*
1121
 
1122
  - `operation_not_permitted` — if on entry `owns` is `false`.
1123
 
1124
+ ##### Modifiers <a id="thread.lock.unique.mod">[[thread.lock.unique.mod]]</a>
1125
 
1126
  ``` cpp
1127
  void swap(unique_lock& u) noexcept;
1128
  ```
1129
 
 
1133
  mutex_type* release() noexcept;
1134
  ```
1135
 
1136
  *Returns:* The previous value of `pm`.
1137
 
1138
+ *Ensures:* `pm == 0` and `owns == false`.
1139
 
1140
  ``` cpp
1141
  template<class Mutex>
1142
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
1143
  ```
1144
 
1145
  *Effects:* As if by `x.swap(y)`.
1146
 
1147
+ ##### Observers <a id="thread.lock.unique.obs">[[thread.lock.unique.obs]]</a>
1148
 
1149
  ``` cpp
1150
  bool owns_lock() const noexcept;
1151
  ```
1152
 
 
1178
  explicit shared_lock(mutex_type& m); // blocking
1179
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
1180
  shared_lock(mutex_type& m, try_to_lock_t);
1181
  shared_lock(mutex_type& m, adopt_lock_t);
1182
  template<class Clock, class Duration>
1183
+ shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
 
1184
  template<class Rep, class Period>
1185
+ shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
 
1186
  ~shared_lock();
1187
 
1188
  shared_lock(const shared_lock&) = delete;
1189
  shared_lock& operator=(const shared_lock&) = delete;
1190
 
 
1212
  private:
1213
  mutex_type* pm; // exposition only
1214
  bool owns; // exposition only
1215
  };
1216
 
 
 
1217
  template<class Mutex>
1218
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1219
  }
1220
  ```
1221
 
 
1224
  may be acquired at construction or after construction, and may be
1225
  transferred, after acquisition, to another `shared_lock` object. Objects
1226
  of type `shared_lock` are not copyable but are movable. The behavior of
1227
  a program is undefined if the contained pointer `pm` is not null and the
1228
  lockable object pointed to by `pm` does not exist for the entire
1229
+ remaining lifetime [[basic.life]] of the `shared_lock` object. The
1230
+ supplied `Mutex` type shall meet the shared mutex requirements
1231
+ [[thread.sharedtimedmutex.requirements]].
1232
 
1233
+ [*Note 1*: `shared_lock<Mutex>` meets the *Cpp17TimedLockable*
1234
+ requirements [[thread.req.lockable.timed]]. — *end note*]
1235
 
1236
+ ##### Constructors, destructor, and assignment <a id="thread.lock.shared.cons">[[thread.lock.shared.cons]]</a>
1237
 
1238
  ``` cpp
1239
  shared_lock() noexcept;
1240
  ```
1241
 
1242
+ *Ensures:* `pm == nullptr` and `owns == false`.
 
 
1243
 
1244
  ``` cpp
1245
  explicit shared_lock(mutex_type& m);
1246
  ```
1247
 
1248
+ *Preconditions:* The calling thread does not own the mutex for any
1249
+ ownership mode.
1250
 
1251
+ *Effects:* Calls `m.lock_shared()`.
 
1252
 
1253
+ *Ensures:* `pm == addressof(m)` and `owns == true`.
1254
 
1255
  ``` cpp
1256
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
1257
  ```
1258
 
1259
+ *Ensures:* `pm == addressof(m)` and `owns == false`.
 
 
1260
 
1261
  ``` cpp
1262
  shared_lock(mutex_type& m, try_to_lock_t);
1263
  ```
1264
 
1265
+ *Preconditions:* The calling thread does not own the mutex for any
1266
+ ownership mode.
1267
 
1268
+ *Effects:* Calls `m.try_lock_shared()`.
 
1269
 
1270
+ *Ensures:* `pm == addressof(m)` and `owns == res` where `res` is the
1271
+ value returned by the call to `m.try_lock_shared()`.
1272
 
1273
  ``` cpp
1274
  shared_lock(mutex_type& m, adopt_lock_t);
1275
  ```
1276
 
1277
+ *Preconditions:* The calling thread has shared ownership of the mutex.
1278
 
1279
+ *Ensures:* `pm == addressof(m)` and `owns == true`.
 
 
1280
 
1281
  ``` cpp
1282
  template<class Clock, class Duration>
1283
  shared_lock(mutex_type& m,
1284
  const chrono::time_point<Clock, Duration>& abs_time);
1285
  ```
1286
 
1287
+ *Preconditions:* The calling thread does not own the mutex for any
1288
+ ownership mode.
1289
 
1290
+ *Effects:* Calls `m.try_lock_shared_until(abs_time)`.
 
1291
 
1292
+ *Ensures:* `pm == addressof(m)` and `owns == res` where `res` is the
1293
+ value returned by the call to `m.try_lock_shared_until(abs_time)`.
1294
 
1295
  ``` cpp
1296
  template<class Rep, class Period>
1297
  shared_lock(mutex_type& m,
1298
  const chrono::duration<Rep, Period>& rel_time);
1299
  ```
1300
 
1301
+ *Preconditions:* The calling thread does not own the mutex for any
1302
+ ownership mode.
1303
 
1304
+ *Effects:* Calls `m.try_lock_shared_for(rel_time)`.
 
1305
 
1306
+ *Ensures:* `pm == addressof(m)` and `owns == res` where `res` is the
1307
+ value returned by the call to `m.try_lock_shared_for(rel_time)`.
1308
 
1309
  ``` cpp
1310
  ~shared_lock();
1311
  ```
1312
 
 
1314
 
1315
  ``` cpp
1316
  shared_lock(shared_lock&& sl) noexcept;
1317
  ```
1318
 
1319
+ *Ensures:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p` is the
1320
+ state of `sl` just prior to this construction), `sl.pm == nullptr` and
1321
+ `sl.owns == false`.
1322
 
1323
  ``` cpp
1324
  shared_lock& operator=(shared_lock&& sl) noexcept;
1325
  ```
1326
 
1327
  *Effects:* If `owns` calls `pm->unlock_shared()`.
1328
 
1329
+ *Ensures:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p` is the
1330
+ state of `sl` just prior to this assignment), `sl.pm == nullptr` and
1331
+ `sl.owns == false`.
1332
 
1333
+ ##### Locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
1334
 
1335
  ``` cpp
1336
  void lock();
1337
  ```
1338
 
1339
  *Effects:* As if by `pm->lock_shared()`.
1340
 
1341
+ *Ensures:* `owns == true`.
1342
 
1343
  *Throws:* Any exception thrown by `pm->lock_shared()`. `system_error`
1344
+ when an exception is required [[thread.req.exception]].
1345
 
1346
  *Error conditions:*
1347
 
1348
  - `operation_not_permitted` — if `pm` is `nullptr`.
1349
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1354
 
1355
  *Effects:* As if by `pm->try_lock_shared()`.
1356
 
1357
  *Returns:* The value returned by the call to `pm->try_lock_shared()`.
1358
 
1359
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1360
+ to `pm->try_lock_shared()`.
1361
 
1362
  *Throws:* Any exception thrown by `pm->try_lock_shared()`.
1363
+ `system_error` when an exception is required [[thread.req.exception]].
 
1364
 
1365
  *Error conditions:*
1366
 
1367
  - `operation_not_permitted` — if `pm` is `nullptr`.
1368
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
1369
 
1370
  ``` cpp
1371
  template<class Clock, class Duration>
1372
+ bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 
1373
  ```
1374
 
1375
  *Effects:* As if by `pm->try_lock_shared_until(abs_time)`.
1376
 
1377
  *Returns:* The value returned by the call to
1378
  `pm->try_lock_shared_until(abs_time)`.
1379
 
1380
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1381
+ to `pm->try_lock_shared_until(abs_time)`.
1382
 
1383
  *Throws:* Any exception thrown by `pm->try_lock_shared_until(abs_time)`.
1384
+ `system_error` when an exception is required [[thread.req.exception]].
 
1385
 
1386
  *Error conditions:*
1387
 
1388
  - `operation_not_permitted` — if `pm` is `nullptr`.
1389
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1396
  *Effects:* As if by `pm->try_lock_shared_for(rel_time)`.
1397
 
1398
  *Returns:* The value returned by the call to
1399
  `pm->try_lock_shared_for(rel_time)`.
1400
 
1401
+ *Ensures:* `owns == res`, where `res` is the value returned by the call
1402
+ to `pm->try_lock_shared_for(rel_time)`.
1403
 
1404
  *Throws:* Any exception thrown by `pm->try_lock_shared_for(rel_time)`.
1405
+ `system_error` when an exception is required [[thread.req.exception]].
 
1406
 
1407
  *Error conditions:*
1408
 
1409
  - `operation_not_permitted` — if `pm` is `nullptr`.
1410
  - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
 
1413
  void unlock();
1414
  ```
1415
 
1416
  *Effects:* As if by `pm->unlock_shared()`.
1417
 
1418
+ *Ensures:* `owns == false`.
1419
 
1420
  *Throws:* `system_error` when an exception is
1421
+ required [[thread.req.exception]].
1422
 
1423
  *Error conditions:*
1424
 
1425
  - `operation_not_permitted` — if on entry `owns` is `false`.
1426
 
1427
+ ##### Modifiers <a id="thread.lock.shared.mod">[[thread.lock.shared.mod]]</a>
1428
 
1429
  ``` cpp
1430
  void swap(shared_lock& sl) noexcept;
1431
  ```
1432
 
 
1436
  mutex_type* release() noexcept;
1437
  ```
1438
 
1439
  *Returns:* The previous value of `pm`.
1440
 
1441
+ *Ensures:* `pm == nullptr` and `owns == false`.
1442
 
1443
  ``` cpp
1444
  template<class Mutex>
1445
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1446
  ```
1447
 
1448
  *Effects:* As if by `x.swap(y)`.
1449
 
1450
+ ##### Observers <a id="thread.lock.shared.obs">[[thread.lock.shared.obs]]</a>
1451
 
1452
  ``` cpp
1453
  bool owns_lock() const noexcept;
1454
  ```
1455
 
 
1471
 
1472
  ``` cpp
1473
  template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
1474
  ```
1475
 
1476
+ *Preconditions:* Each template parameter type meets the *Cpp17Lockable*
1477
  requirements.
1478
 
1479
  [*Note 1*: The `unique_lock` class template meets these requirements
1480
  when suitably instantiated. — *end note*]
1481
 
1482
  *Effects:* Calls `try_lock()` for each argument in order beginning with
1483
  the first until all arguments have been processed or a call to
1484
  `try_lock()` fails, either by returning `false` or by throwing an
1485
+ exception. If a call to `try_lock()` fails, `unlock()` is called for all
1486
+ prior arguments with no further calls to `try_lock()`.
 
1487
 
1488
  *Returns:* `-1` if all calls to `try_lock()` returned `true`, otherwise
1489
  a zero-based index value that indicates the argument for which
1490
  `try_lock()` returned `false`.
1491
 
1492
  ``` cpp
1493
  template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
1494
  ```
1495
 
1496
+ *Preconditions:* Each template parameter type meets the *Cpp17Lockable*
1497
+ requirements.
1498
 
1499
  [*Note 2*: The `unique_lock` class template meets these requirements
1500
  when suitably instantiated. — *end note*]
1501
 
1502
  *Effects:* All arguments are locked via a sequence of calls to `lock()`,
1503
+ `try_lock()`, or `unlock()` on each argument. The sequence of calls does
1504
+ not result in deadlock, but is otherwise unspecified.
1505
 
1506
  [*Note 3*: A deadlock avoidance algorithm such as try-and-back-off must
1507
  be used, but the specific algorithm is not specified to avoid
1508
  over-constraining implementations. — *end note*]
1509
 
1510
+ If a call to `lock()` or `try_lock()` throws an exception, `unlock()` is
1511
+ called for any argument that had been locked by a call to `lock()` or
1512
+ `try_lock()`.
1513
 
1514
  ### Call once <a id="thread.once">[[thread.once]]</a>
1515
 
1516
  #### Struct `once_flag` <a id="thread.once.onceflag">[[thread.once.onceflag]]</a>
1517
 
 
1531
 
1532
  ``` cpp
1533
  constexpr once_flag() noexcept;
1534
  ```
1535
 
 
 
1536
  *Synchronization:* The construction of a `once_flag` object is not
1537
  synchronized.
1538
 
1539
+ *Ensures:* The object’s internal state is set to indicate to an
1540
  invocation of `call_once` with the object as its initial argument that
1541
  no function has been called.
1542
 
1543
  #### Function `call_once` <a id="thread.once.callonce">[[thread.once.callonce]]</a>
1544
 
1545
  ``` cpp
1546
  template<class Callable, class... Args>
1547
  void call_once(once_flag& flag, Callable&& func, Args&&... args);
1548
  ```
1549
 
1550
+ *Mandates:* `is_invocable_v<Callable, Args...>` is `true`.
 
 
 
 
 
 
1551
 
1552
  *Effects:* An execution of `call_once` that does not call its `func` is
1553
  a *passive* execution. An execution of `call_once` that calls its `func`
1554
+ is an *active* execution. An active execution calls *INVOKE*(
1555
  std::forward\<Callable\>(func), std::forward\<Args\>(args)...). If such
1556
  a call to `func` throws an exception the execution is *exceptional*,
1557
+ otherwise it is *returning*. An exceptional execution propagates the
1558
+ exception to the caller of `call_once`. Among all executions of
1559
+ `call_once` for any given `once_flag`: at most one is a returning
1560
+ execution; if there is a returning execution, it is the last active
1561
+ execution; and there are passive executions only if there is a returning
1562
+ execution.
1563
 
1564
  [*Note 1*: Passive executions allow other threads to reliably observe
1565
  the results produced by the earlier returning execution. — *end note*]
1566
 
1567
  *Synchronization:* For any given `once_flag`: all active executions
1568
  occur in a total order; completion of an active execution synchronizes
1569
+ with [[intro.multithread]] the start of the next one in this total
1570
  order; and the returning execution synchronizes with the return from all
1571
  passive executions.
1572
 
1573
  *Throws:* `system_error` when an exception is
1574
+ required [[thread.req.exception]], or any exception thrown by `func`.
1575
 
1576
  [*Example 1*:
1577
 
1578
  ``` cpp
1579
  // global flag, regular function