From Jason Turner

[thread.mutex]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpcfl9g71u/{from.md → to.md} +544 -37
tmp/tmpcfl9g71u/{from.md → to.md} RENAMED
@@ -34,11 +34,20 @@ namespace std {
34
  once_flag(const once_flag&) = delete;
35
  once_flag& operator=(const once_flag&) = delete;
36
  };
37
 
38
  template<class Callable, class ...Args>
39
- void call_once(once_flag& flag, Callable func, Args&&... args);
 
 
 
 
 
 
 
 
 
40
  }
41
  ```
42
 
43
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
44
 
@@ -47,22 +56,20 @@ namespace std {
47
  A mutex object facilitates protection against data races and allows safe
48
  synchronization of data between execution agents (
49
  [[thread.req.lockable]]). An execution agent *owns* a mutex from the
50
  time it successfully calls one of the lock functions until it calls
51
  unlock. Mutexes can be either recursive or non-recursive, and can grant
52
- simultaneous ownership to one or many execution agents. The mutex types
53
- supplied by the standard library provide exclusive ownership semantics:
54
- only one thread may own the mutex at a time. Both recursive and
55
- non-recursive mutexes are supplied.
56
 
57
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
58
 
59
  The *mutex types* are the standard library types `std::mutex`,
60
- `std::recursive_mutex`, `std::timed_mutex`, and
61
- `std::recursive_timed_mutex`. They shall meet the requirements set out
62
- in this section. In this description, `m` denotes an object of a mutex
63
- type.
64
 
65
  The mutex types shall meet the `Lockable` requirements (
66
  [[thread.req.lockable.req]]).
67
 
68
  The mutex types shall be `DefaultConstructible` and `Destructible`. If
@@ -93,12 +100,12 @@ should be used to ensure that mutex objects are initialized and visible
93
  to other threads.
94
 
95
  The expression `m.lock()` shall be well-formed and have the following
96
  semantics:
97
 
98
- *Requires:* If `m` is of type `std::mutex` or `std::timed_mutex`, the
99
- calling thread does not own the mutex.
100
 
101
  *Effects:* Blocks the calling thread until ownership of the mutex can be
102
  obtained for the calling thread.
103
 
104
  The calling thread owns the mutex.
@@ -121,12 +128,12 @@ required ([[thread.req.exception]]).
121
  blocking is not possible.
122
 
123
  The expression `m.try_lock()` shall be well-formed and have the
124
  following semantics:
125
 
126
- *Requires:* If `m` is of type `std::mutex` or `std::timed_mutex`, the
127
- calling thread does not own the mutex.
128
 
129
  *Effects:* Attempts to obtain ownership of the mutex for the calling
130
  thread without blocking. If ownership is not obtained, there is no
131
  effect and `try_lock()` immediately returns. An implementation may fail
132
  to obtain the lock even if it is not held by any other thread. This
@@ -157,12 +164,12 @@ The calling thread shall own the mutex.
157
 
158
  *Effects:* Releases the calling thread’s ownership of the mutex.
159
 
160
  *Return type:* `void`
161
 
162
- *Synchronization:* This operation *synchronizes
163
- with* ([[intro.multithread]]) subsequent lock operations that obtain
164
  ownership on the same object.
165
 
166
  *Throws:* Nothing.
167
 
168
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
@@ -263,26 +270,25 @@ The behavior of a program is undefined if:
263
  - a thread terminates while owning a `recursive_mutex` object.
264
 
265
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
266
 
267
  The *timed mutex types* are the standard library types
268
- `std::timed_mutex` and `std::recursive_timed_mutex`. They shall meet the
269
- requirements set out below. In this description, `m` denotes an object
270
- of a mutex type, `rel_time` denotes an object of an instantiation of
271
- `duration` ([[time.duration]]), and `abs_time` denotes an object of an
272
- instantiation of `time_point` ([[time.point]]).
 
273
 
274
  The timed mutex types shall meet the `TimedLockable` requirements (
275
  [[thread.req.lockable.timed]]).
276
 
277
  The expression `m.try_lock_for(rel_time)` shall be well-formed and have
278
  the following semantics:
279
 
280
- If the tick `period` of `rel_time` is not exactly convertible to the
281
- native tick `period`, the `duration` shall be rounded up to the nearest
282
- native tick `period`. If `m` is of type `std::timed_mutex`, the calling
283
- thread does not own the mutex.
284
 
285
  *Effects:* The function attempts to obtain ownership of the mutex within
286
  the relative timeout ([[thread.req.timing]]) specified by `rel_time`.
287
  If the time specified by `rel_time` is less than or equal to
288
  `rel_time.zero()`, the function attempts to obtain ownership without
@@ -298,17 +304,17 @@ implementations are expected to make a strong effort to do so.
298
 
299
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
300
  operations on the same object *synchronize
301
  with* ([[intro.multithread]]) this operation.
302
 
303
- *Throws:* Nothing.
304
 
305
  The expression `m.try_lock_until(abs_time)` shall be well-formed and
306
  have the following semantics:
307
 
308
- *Requires:* If `m` is of type `std::timed_mutex`, the calling thread
309
- does not own the mutex.
310
 
311
  *Effects:* The function attempts to obtain ownership of the mutex. If
312
  `abs_time` has already passed, the function attempts to obtain ownership
313
  without blocking (as if by calling `try_lock()`). The function shall
314
  return before the absolute timeout ([[thread.req.timing]]) specified by
@@ -323,11 +329,11 @@ strong effort to do so.
323
 
324
  *Synchronization:* If `try_lock_until()` returns `true`, prior
325
  `unlock()` operations on the same object *synchronize
326
  with* ([[intro.multithread]]) this operation.
327
 
328
- *Throws:* Nothing.
329
 
330
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
331
 
332
  ``` cpp
333
  namespace std {
@@ -337,11 +343,11 @@ namespace std {
337
  ~timed_mutex();
338
 
339
  timed_mutex(const timed_mutex&) = delete;
340
  timed_mutex& operator=(const timed_mutex&) = delete;
341
 
342
- void lock();
343
  bool try_lock();
344
  template <class Rep, class Period>
345
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
346
  template <class Clock, class Duration>
347
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
@@ -383,11 +389,11 @@ namespace std {
383
  ~recursive_timed_mutex();
384
 
385
  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
386
  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
387
 
388
- void lock();
389
  bool try_lock() noexcept;
390
  template <class Rep, class Period>
391
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
392
  template <class Clock, class Duration>
393
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
@@ -427,10 +433,204 @@ the object be acquired by another thread.
427
  The behavior of a program is undefined if:
428
 
429
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
430
  - a thread terminates while owning a `recursive_timed_mutex` object.
431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  ### Locks <a id="thread.lock">[[thread.lock]]</a>
433
 
434
  A *lock* is an object that holds a reference to a lockable object and
435
  may unlock the lockable object during the lock’s destruction (such as
436
  when leaving block scope). An execution agent may use a lock to aid in
@@ -538,11 +738,11 @@ namespace std {
538
 
539
  unique_lock(unique_lock const&) = delete;
540
  unique_lock& operator=(unique_lock const&) = delete;
541
 
542
  unique_lock(unique_lock&& u) noexcept;
543
- unique_lock& operator=(unique_lock&& u) noexcept;
544
 
545
  // [thread.lock.unique.locking], locking:
546
  void lock();
547
  bool try_lock();
548
 
@@ -682,11 +882,11 @@ unique_lock(unique_lock&& u) noexcept;
682
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
683
  the state of `u` just prior to this construction), `u.pm == 0` and
684
  `u.owns == false`.
685
 
686
  ``` cpp
687
- unique_lock& operator=(unique_lock&& u) noexcept;
688
  ```
689
 
690
  *Effects:* If `owns` calls `pm->unlock()`.
691
 
692
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
@@ -695,10 +895,12 @@ the state of `u` just prior to this construction), `u.pm == 0` and
695
 
696
  With a recursive mutex it is possible for both `*this` and `u` to own
697
  the same mutex before the assignment. In this case, `*this` will own the
698
  mutex after the assignment and `u` will not.
699
 
 
 
700
  ``` cpp
701
  ~unique_lock();
702
  ```
703
 
704
  *Effects:* If `owns` calls `pm->unlock()`.
@@ -837,10 +1039,319 @@ explicit operator bool() const noexcept;
837
  mutex_type *mutex() const noexcept;
838
  ```
839
 
840
  *Returns:* `pm`
841
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
842
  ### Generic locking algorithms <a id="thread.lock.algorithm">[[thread.lock.algorithm]]</a>
843
 
844
  ``` cpp
845
  template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
846
  ```
@@ -852,11 +1363,11 @@ when suitably instantiated.
852
  *Effects:* Calls `try_lock()` for each argument in order beginning with
853
  the first until all arguments have been processed or a call to
854
  `try_lock()` fails, either by returning `false` or by throwing an
855
  exception. If a call to `try_lock()` fails, `unlock()` shall be called
856
  for all prior arguments and there shall be no further calls to
857
- try_lock().
858
 
859
  *Returns:* `-1` if all calls to `try_lock()` returned `true`, otherwise
860
  a 0-based index value that indicates the argument for which `try_lock()`
861
  returned `false`.
862
 
@@ -931,14 +1442,10 @@ order; and the returning execution synchronizes with the return from all
931
  passive executions.
932
 
933
  *Throws:* `system_error` when an exception is
934
  required ([[thread.req.exception]]), or any exception thrown by `func`.
935
 
936
- *Error conditions:*
937
-
938
- - `invalid_argument` — if the `once_flag` object is no longer valid.
939
-
940
  ``` cpp
941
  // global flag, regular function
942
  void init();
943
  std::once_flag flag;
944
 
 
34
  once_flag(const once_flag&) = delete;
35
  once_flag& operator=(const once_flag&) = delete;
36
  };
37
 
38
  template<class Callable, class ...Args>
39
+ void call_once(once_flag& flag, Callable&& func, Args&&... args);
40
+ }
41
+ ```
42
+
43
+ ``` cpp
44
+ namespace std {
45
+ class shared_timed_mutex;
46
+ template <class Mutex> class shared_lock;
47
+ template <class Mutex>
48
+ void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
49
  }
50
  ```
51
 
52
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
53
 
 
56
  A mutex object facilitates protection against data races and allows safe
57
  synchronization of data between execution agents (
58
  [[thread.req.lockable]]). An execution agent *owns* a mutex from the
59
  time it successfully calls one of the lock functions until it calls
60
  unlock. Mutexes can be either recursive or non-recursive, and can grant
61
+ simultaneous ownership to one or many execution agents. Both recursive
62
+ and non-recursive mutexes are supplied.
 
 
63
 
64
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
65
 
66
  The *mutex types* are the standard library types `std::mutex`,
67
+ `std::recursive_mutex`, `std::timed_mutex`,
68
+ `std::recursive_timed_mutex`, and `std::shared_timed_mutex`. They shall
69
+ meet the requirements set out in this section. In this description, `m`
70
+ denotes an object of a mutex type.
71
 
72
  The mutex types shall meet the `Lockable` requirements (
73
  [[thread.req.lockable.req]]).
74
 
75
  The mutex types shall be `DefaultConstructible` and `Destructible`. If
 
100
  to other threads.
101
 
102
  The expression `m.lock()` shall be well-formed and have the following
103
  semantics:
104
 
105
+ *Requires:* If `m` is of type `std::mutex`, `std::timed_mutex`, or
106
+ `std::shared_timed_mutex`, the calling thread does not own the mutex.
107
 
108
  *Effects:* Blocks the calling thread until ownership of the mutex can be
109
  obtained for the calling thread.
110
 
111
  The calling thread owns the mutex.
 
128
  blocking is not possible.
129
 
130
  The expression `m.try_lock()` shall be well-formed and have the
131
  following semantics:
132
 
133
+ *Requires:* If `m` is of type `std::mutex`, `std::timed_mutex`, or
134
+ `std::shared_timed_mutex`, the calling thread does not own the mutex.
135
 
136
  *Effects:* Attempts to obtain ownership of the mutex for the calling
137
  thread without blocking. If ownership is not obtained, there is no
138
  effect and `try_lock()` immediately returns. An implementation may fail
139
  to obtain the lock even if it is not held by any other thread. This
 
164
 
165
  *Effects:* Releases the calling thread’s ownership of the mutex.
166
 
167
  *Return type:* `void`
168
 
169
+ *Synchronization:* This operation synchronizes
170
+ with ([[intro.multithread]]) subsequent lock operations that obtain
171
  ownership on the same object.
172
 
173
  *Throws:* Nothing.
174
 
175
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
 
270
  - a thread terminates while owning a `recursive_mutex` object.
271
 
272
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
273
 
274
  The *timed mutex types* are the standard library types
275
+ `std::timed_mutex`, `std::recursive_timed_mutex`, and
276
+ `std::shared_timed_mutex`. They shall meet the requirements set out
277
+ below. In this description, `m` denotes an object of a mutex type,
278
+ `rel_time` denotes an object of an instantiation of `duration` (
279
+ [[time.duration]]), and `abs_time` denotes an object of an instantiation
280
+ of `time_point` ([[time.point]]).
281
 
282
  The timed mutex types shall meet the `TimedLockable` requirements (
283
  [[thread.req.lockable.timed]]).
284
 
285
  The expression `m.try_lock_for(rel_time)` shall be well-formed and have
286
  the following semantics:
287
 
288
+ If `m` is of type `std::timed_mutex` or `std::shared_timed_mutex`, the
289
+ calling thread does not own the mutex.
 
 
290
 
291
  *Effects:* The function attempts to obtain ownership of the mutex within
292
  the relative timeout ([[thread.req.timing]]) specified by `rel_time`.
293
  If the time specified by `rel_time` is less than or equal to
294
  `rel_time.zero()`, the function attempts to obtain ownership without
 
304
 
305
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
306
  operations on the same object *synchronize
307
  with* ([[intro.multithread]]) this operation.
308
 
309
+ *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
310
 
311
  The expression `m.try_lock_until(abs_time)` shall be well-formed and
312
  have the following semantics:
313
 
314
+ *Requires:* If `m` is of type `std::timed_mutex` or
315
+ `std::shared_timed_mutex`, the calling thread does not own the mutex.
316
 
317
  *Effects:* The function attempts to obtain ownership of the mutex. If
318
  `abs_time` has already passed, the function attempts to obtain ownership
319
  without blocking (as if by calling `try_lock()`). The function shall
320
  return before the absolute timeout ([[thread.req.timing]]) specified by
 
329
 
330
  *Synchronization:* If `try_lock_until()` returns `true`, prior
331
  `unlock()` operations on the same object *synchronize
332
  with* ([[intro.multithread]]) this operation.
333
 
334
+ *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
335
 
336
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
337
 
338
  ``` cpp
339
  namespace std {
 
343
  ~timed_mutex();
344
 
345
  timed_mutex(const timed_mutex&) = delete;
346
  timed_mutex& operator=(const timed_mutex&) = delete;
347
 
348
+ void lock(); // blocking
349
  bool try_lock();
350
  template <class Rep, class Period>
351
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
352
  template <class Clock, class Duration>
353
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 
389
  ~recursive_timed_mutex();
390
 
391
  recursive_timed_mutex(const recursive_timed_mutex&) = delete;
392
  recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
393
 
394
+ void lock(); // blocking
395
  bool try_lock() noexcept;
396
  template <class Rep, class Period>
397
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
398
  template <class Clock, class Duration>
399
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
 
433
  The behavior of a program is undefined if:
434
 
435
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
436
  - a thread terminates while owning a `recursive_timed_mutex` object.
437
 
438
+ #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
439
+
440
+ The standard library type `std::shared_timed_mutex` is a *shared timed
441
+ mutex type*. Shared timed mutex types shall meet the requirements of
442
+ timed mutex types ([[thread.timedmutex.requirements]]), and
443
+ additionally shall meet the requirements set out below. In this
444
+ description, `m` denotes an object of a mutex type, `rel_type` denotes
445
+ an object of an instantiation of `duration` ([[time.duration]]), and
446
+ `abs_time` denotes an object of an instantiation of `time_point` (
447
+ [[time.point]]).
448
+
449
+ In addition to the exclusive lock ownership mode specified in 
450
+ [[thread.mutex.requirements.mutex]], shared mutex types provide a
451
+ *shared lock* ownership mode. Multiple execution agents can
452
+ simultaneously hold a shared lock ownership of a shared mutex type. But
453
+ no execution agent shall hold a shared lock while another execution
454
+ agent holds an exclusive lock on the same shared mutex type, and
455
+ vice-versa. The maximum number of execution agents which can share a
456
+ shared lock on a single shared mutex type is unspecified, but shall be
457
+ at least 10000. If more than the maximum number of execution agents
458
+ attempt to obtain a shared lock, the excess execution agents shall block
459
+ until the number of shared locks are reduced below the maximum amount by
460
+ other execution agents releasing their shared lock.
461
+
462
+ The expression `m.lock_shared()` shall be well-formed and have the
463
+ following semantics:
464
+
465
+ *Requires:* The calling thread has no ownership of the mutex.
466
+
467
+ *Effects:* Blocks the calling thread until shared ownership of the mutex
468
+ can be obtained for the calling thread. If an exception is thrown then a
469
+ shared lock shall not have been acquired for the current thread.
470
+
471
+ The calling thread has a shared lock on the mutex.
472
+
473
+ *Return type:* `void`.
474
+
475
+ *Synchronization:* Prior `unlock()` operations on the same object shall
476
+ synchronize with  ([[intro.multithread]]) this operation.
477
+
478
+ *Throws:* `system_error` when an exception is required
479
+  ([[thread.req.exception]]).
480
+
481
+ *Error conditions:*
482
+
483
+ - `operation_not_permitted` — if the thread does not have the privilege
484
+ to perform the operation.
485
+ - `resource_deadlock_would_occur` — if the implementation detects that a
486
+ deadlock would occur.
487
+ - `device_or_resource_busy` — if the mutex is already locked and
488
+ blocking is not possible.
489
+
490
+ The expression `m.unlock_shared()` shall be well-formed and have the
491
+ following semantics:
492
+
493
+ *Requires:* The calling thread shall hold a shared lock on the mutex.
494
+
495
+ *Effects:* Releases a shared lock on the mutex held by the calling
496
+ thread.
497
+
498
+ *Return type:* `void`.
499
+
500
+ *Synchronization:* This operation synchronizes
501
+ with ([[intro.multithread]]) subsequent `lock()` operations that obtain
502
+ ownership on the same object.
503
+
504
+ *Throws:* Nothing.
505
+
506
+ The expression `m.try_lock_shared()` shall be well-formed and have the
507
+ following semantics:
508
+
509
+ *Requires:* The calling thread has no ownership of the mutex.
510
+
511
+ *Effects:* Attempts to obtain shared ownership of the mutex for the
512
+ calling thread without blocking. If shared ownership is not obtained,
513
+ there is no effect and `try_lock_shared()` immediately returns. An
514
+ implementation may fail to obtain the lock even if it is not held by any
515
+ other thread.
516
+
517
+ *Return type:* `bool`.
518
+
519
+ *Returns:* `true` if the shared ownership lock was acquired, `false`
520
+ otherwise.
521
+
522
+ *Synchronization:* If `try_lock_shared()` returns `true`, prior
523
+ `unlock()` operations on the same object synchronize with
524
+  ([[intro.multithread]]) this operation.
525
+
526
+ *Throws:* Nothing.
527
+
528
+ The expression `m.try_lock_shared_for(rel_time)` shall be well-formed
529
+ and have the following semantics:
530
+
531
+ *Requires:* The calling thread has no ownership of the mutex.
532
+
533
+ *Effects:* Attempts to obtain shared lock ownership for the calling
534
+ thread within the relative timeout ([[thread.req.timing]]) specified by
535
+ `rel_time`. If the time specified by `rel_time` is less than or equal to
536
+ `rel_time.zero()`, the function attempts to obtain ownership without
537
+ blocking (as if by calling `try_lock_shared()`). The function shall
538
+ return within the timeout specified by `rel_time` only if it has
539
+ obtained shared ownership of the mutex object. As with `try_lock()`,
540
+ there is no guarantee that ownership will be obtained if the lock is
541
+ available, but implementations are expected to make a strong effort to
542
+ do so. If an exception is thrown then a shared lock shall not have been
543
+ acquired for the current thread.
544
+
545
+ *Return type:* `bool`.
546
+
547
+ *Returns:* `true` if the shared lock was acquired, `false` otherwise.
548
+
549
+ *Synchronization:* If `try_lock_shared_for()` returns `true`, prior
550
+ `unlock()` operations on the same object synchronize
551
+ with ([[intro.multithread]]) this operation.
552
+
553
+ *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
554
+
555
+ The expression `m.try_lock_shared_until(abs_time)` shall be well-formed
556
+ and have the following semantics:
557
+
558
+ *Requires:* The calling thread has no ownership of the mutex.
559
+
560
+ *Effects:* The function attempts to obtain shared ownership of the
561
+ mutex. If `abs_time` has already passed, the function attempts to obtain
562
+ shared ownership without blocking (as if by calling
563
+ `try_lock_shared()`). The function shall return before the absolute
564
+ timeout ([[thread.req.timing]]) specified by `abs_time` only if it has
565
+ obtained shared ownership of the mutex object. As with `try_lock()`,
566
+ there is no guarantee that ownership will be obtained if the lock is
567
+ available, but implementations are expected to make a strong effort to
568
+ do so. If an exception is thrown then a shared lock shall not have been
569
+ acquired for the current thread.
570
+
571
+ *Return type:* `bool`.
572
+
573
+ *Returns:* `true` if the shared lock was acquired, `false` otherwise.
574
+
575
+ *Synchronization:* If `try_lock_shared_until()` returns `true`, prior
576
+ `unlock()` operations on the same object synchronize
577
+ with ([[intro.multithread]]) this operation.
578
+
579
+ *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
580
+
581
+ ##### Class `shared_timed_mutex` <a id="thread.sharedtimedmutex.class">[[thread.sharedtimedmutex.class]]</a>
582
+
583
+ ``` cpp
584
+ namespace std {
585
+ class shared_timed_mutex {
586
+ public:
587
+ shared_timed_mutex();
588
+ ~shared_timed_mutex();
589
+
590
+ shared_timed_mutex(const shared_timed_mutex&) = delete;
591
+ shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
592
+
593
+ // Exclusive ownership
594
+ void lock(); // blocking
595
+ bool try_lock();
596
+ template <class Rep, class Period>
597
+ bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
598
+ template <class Clock, class Duration>
599
+ bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
600
+ void unlock();
601
+
602
+ // Shared ownership
603
+ void lock_shared(); // blocking
604
+ bool try_lock_shared();
605
+ template <class Rep, class Period>
606
+ bool
607
+ try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
608
+ template <class Clock, class Duration>
609
+ bool
610
+ try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
611
+ void unlock_shared();
612
+ };
613
+ }
614
+ ```
615
+
616
+ The class `shared_timed_mutex` provides a non-recursive mutex with
617
+ shared ownership semantics.
618
+
619
+ The class `shared_timed_mutex` shall satisfy all of the
620
+ `SharedTimedMutex` requirements (
621
+ [[thread.sharedtimedmutex.requirements]]). It shall be a standard-layout
622
+ class (Clause  [[class]]).
623
+
624
+ The behavior of a program is undefined if:
625
+
626
+ - it destroys a `shared_timed_mutex` object owned by any thread,
627
+ - a thread attempts to recursively gain any ownership of a
628
+ `shared_timed_mutex`, or
629
+ - a thread terminates while possessing any ownership of a
630
+ `shared_timed_mutex`.
631
+
632
  ### Locks <a id="thread.lock">[[thread.lock]]</a>
633
 
634
  A *lock* is an object that holds a reference to a lockable object and
635
  may unlock the lockable object during the lock’s destruction (such as
636
  when leaving block scope). An execution agent may use a lock to aid in
 
738
 
739
  unique_lock(unique_lock const&) = delete;
740
  unique_lock& operator=(unique_lock const&) = delete;
741
 
742
  unique_lock(unique_lock&& u) noexcept;
743
+ unique_lock& operator=(unique_lock&& u);
744
 
745
  // [thread.lock.unique.locking], locking:
746
  void lock();
747
  bool try_lock();
748
 
 
882
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
883
  the state of `u` just prior to this construction), `u.pm == 0` and
884
  `u.owns == false`.
885
 
886
  ``` cpp
887
+ unique_lock& operator=(unique_lock&& u);
888
  ```
889
 
890
  *Effects:* If `owns` calls `pm->unlock()`.
891
 
892
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
 
895
 
896
  With a recursive mutex it is possible for both `*this` and `u` to own
897
  the same mutex before the assignment. In this case, `*this` will own the
898
  mutex after the assignment and `u` will not.
899
 
900
+ *Throws:* Nothing.
901
+
902
  ``` cpp
903
  ~unique_lock();
904
  ```
905
 
906
  *Effects:* If `owns` calls `pm->unlock()`.
 
1039
  mutex_type *mutex() const noexcept;
1040
  ```
1041
 
1042
  *Returns:* `pm`
1043
 
1044
+ #### Class template `shared_lock` <a id="thread.lock.shared">[[thread.lock.shared]]</a>
1045
+
1046
+ ``` cpp
1047
+ namespace std {
1048
+
1049
+ template <class Mutex>
1050
+ class shared_lock {
1051
+ public:
1052
+ typedef Mutex mutex_type;
1053
+
1054
+ // Shared locking
1055
+ shared_lock() noexcept;
1056
+ explicit shared_lock(mutex_type& m); // blocking
1057
+ shared_lock(mutex_type& m, defer_lock_t) noexcept;
1058
+ shared_lock(mutex_type& m, try_to_lock_t);
1059
+ shared_lock(mutex_type& m, adopt_lock_t);
1060
+ template <class Clock, class Duration>
1061
+ shared_lock(mutex_type& m,
1062
+ const chrono::time_point<Clock, Duration>& abs_time);
1063
+ template <class Rep, class Period>
1064
+ shared_lock(mutex_type& m,
1065
+ const chrono::duration<Rep, Period>& rel_time);
1066
+ ~shared_lock();
1067
+
1068
+ shared_lock(shared_lock const&) = delete;
1069
+ shared_lock& operator=(shared_lock const&) = delete;
1070
+
1071
+ shared_lock(shared_lock&& u) noexcept;
1072
+ shared_lock& operator=(shared_lock&& u) noexcept;
1073
+
1074
+ void lock(); // blocking
1075
+ bool try_lock();
1076
+ template <class Rep, class Period>
1077
+ bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1078
+ template <class Clock, class Duration>
1079
+ bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1080
+ void unlock();
1081
+
1082
+ // Setters
1083
+ void swap(shared_lock& u) noexcept;
1084
+ mutex_type* release() noexcept;
1085
+
1086
+ // Getters
1087
+ bool owns_lock() const noexcept;
1088
+ explicit operator bool () const noexcept;
1089
+ mutex_type* mutex() const noexcept;
1090
+
1091
+ private:
1092
+ mutex_type* pm; // exposition only
1093
+ bool owns; // exposition only
1094
+ };
1095
+
1096
+ template <class Mutex>
1097
+ void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1098
+
1099
+ } // std
1100
+ ```
1101
+
1102
+ An object of type `shared_lock` controls the shared ownership of a
1103
+ lockable object within a scope. Shared ownership of the lockable object
1104
+ may be acquired at construction or after construction, and may be
1105
+ transferred, after acquisition, to another `shared_lock` object. Objects
1106
+ of type `shared_lock` are not copyable but are movable. The behavior of
1107
+ a program is undefined if the contained pointer `pm` is not null and the
1108
+ lockable object pointed to by `pm` does not exist for the entire
1109
+ remaining lifetime ([[basic.life]]) of the `shared_lock` object. The
1110
+ supplied `Mutex` type shall meet the shared mutex requirements (
1111
+ [[thread.sharedtimedmutex.requirements]]).
1112
+
1113
+ `shared_lock<Mutex>` meets the `TimedLockable` requirements (
1114
+ [[thread.req.lockable.timed]]).
1115
+
1116
+ ##### `shared_lock` constructors, destructor, and assignment <a id="thread.lock.shared.cons">[[thread.lock.shared.cons]]</a>
1117
+
1118
+ ``` cpp
1119
+ shared_lock() noexcept;
1120
+ ```
1121
+
1122
+ *Effects:* Constructs an object of type `shared_lock`.
1123
+
1124
+ *Postconditions:* `pm == nullptr` and `owns == false`.
1125
+
1126
+ ``` cpp
1127
+ explicit shared_lock(mutex_type& m);
1128
+ ```
1129
+
1130
+ *Requires:* The calling thread does not own the mutex for any ownership
1131
+ mode.
1132
+
1133
+ *Effects:* Constructs an object of type `shared_lock` and calls
1134
+ `m.lock_shared()`.
1135
+
1136
+ *Postconditions:* `pm == &m` and `owns == true`.
1137
+
1138
+ ``` cpp
1139
+ shared_lock(mutex_type& m, defer_lock_t) noexcept;
1140
+ ```
1141
+
1142
+ *Effects:* Constructs an object of type `shared_lock`.
1143
+
1144
+ *Postconditions:* `pm == &m` and `owns == false`.
1145
+
1146
+ ``` cpp
1147
+ shared_lock(mutex_type& m, try_to_lock_t);
1148
+ ```
1149
+
1150
+ *Requires:* The calling thread does not own the mutex for any ownership
1151
+ mode.
1152
+
1153
+ *Effects:* Constructs an object of type `shared_lock` and calls
1154
+ `m.try_lock_shared()`.
1155
+
1156
+ *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
1157
+ returned by the call to `m.try_lock_shared()`.
1158
+
1159
+ ``` cpp
1160
+ shared_lock(mutex_type& m, adopt_lock_t);
1161
+ ```
1162
+
1163
+ *Requires:* The calling thread has shared ownership of the mutex.
1164
+
1165
+ *Effects:* Constructs an object of type `shared_lock`.
1166
+
1167
+ *Postconditions:* `pm == &m` and `owns == true`.
1168
+
1169
+ ``` cpp
1170
+ template <class Clock, class Duration>
1171
+ shared_lock(mutex_type& m,
1172
+ const chrono::time_point<Clock, Duration>& abs_time);
1173
+ ```
1174
+
1175
+ *Requires:* The calling thread does not own the mutex for any ownership
1176
+ mode.
1177
+
1178
+ *Effects:* Constructs an object of type `shared_lock` and calls
1179
+ `m.try_lock_shared_until(abs_time)`.
1180
+
1181
+ *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
1182
+ returned by the call to `m.try_lock_shared_until(abs_time)`.
1183
+
1184
+ ``` cpp
1185
+ template <class Rep, class Period>
1186
+ shared_lock(mutex_type& m,
1187
+ const chrono::duration<Rep, Period>& rel_time);
1188
+ ```
1189
+
1190
+ *Requires:* The calling thread does not own the mutex for any ownership
1191
+ mode.
1192
+
1193
+ *Effects:* Constructs an object of type `shared_lock` and calls
1194
+ `m.try_lock_shared_for(rel_time)`.
1195
+
1196
+ *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
1197
+ returned by the call to `m.try_lock_shared_for(rel_time)`.
1198
+
1199
+ ``` cpp
1200
+ ~shared_lock();
1201
+ ```
1202
+
1203
+ *Effects:* If `owns` calls `pm->unlock_shared()`.
1204
+
1205
+ ``` cpp
1206
+ shared_lock(shared_lock&& sl) noexcept;
1207
+ ```
1208
+
1209
+ *Postconditions:* `pm == &sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
1210
+ is the state of `sl` just prior to this construction),
1211
+ `sl.pm == nullptr` and `sl.owns == false`.
1212
+
1213
+ ``` cpp
1214
+ shared_lock& operator=(shared_lock&& sl) noexcept;
1215
+ ```
1216
+
1217
+ *Effects:* If `owns` calls `pm->unlock_shared()`.
1218
+
1219
+ *Postconditions:* `pm == &sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
1220
+ is the state of `sl` just prior to this assignment), `sl.pm == nullptr`
1221
+ and `sl.owns == false`.
1222
+
1223
+ ##### `shared_lock` locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
1224
+
1225
+ ``` cpp
1226
+ void lock();
1227
+ ```
1228
+
1229
+ *Effects:* `pm->lock_shared()`.
1230
+
1231
+ *Postconditions:* `owns == true`.
1232
+
1233
+ *Throws:* Any exception thrown by `pm->lock_shared()`. `system_error` if
1234
+ an exception is required ([[thread.req.exception]]). `system_error`
1235
+ with an error condition of `operation_not_permitted` if `pm` is
1236
+ `nullptr`. `system_error` with an error condition of
1237
+ `resource_deadlock_would_occur` if on entry `owns` is `true`.
1238
+
1239
+ ``` cpp
1240
+ bool try_lock();
1241
+ ```
1242
+
1243
+ *Effects:* `pm->try_lock_shared()`.
1244
+
1245
+ *Returns:* The value returned by the call to `pm->try_lock_shared()`.
1246
+
1247
+ *Postconditions:* `owns == res`, where `res` is the value returned by
1248
+ the call to `pm->try_lock_shared()`.
1249
+
1250
+ *Throws:* Any exception thrown by `pm->try_lock_shared()`.
1251
+ `system_error` if an exception is required ([[thread.req.exception]]).
1252
+ `system_error` with an error condition of `operation_not_permitted` if
1253
+ `pm` is `nullptr`. `system_error` with an error condition of
1254
+ `resource_deadlock_would_occur` if on entry `owns` is `true`.
1255
+
1256
+ ``` cpp
1257
+ template <class Clock, class Duration>
1258
+ bool
1259
+ try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
1260
+ ```
1261
+
1262
+ *Effects:* `pm->try_lock_shared_until(abs_time)`.
1263
+
1264
+ *Returns:* The value returned by the call to
1265
+ `pm->try_lock_shared_until(abs_time)`.
1266
+
1267
+ *Postconditions:* `owns == res`, where `res` is the value returned by
1268
+ the call to `pm->try_lock_shared_until(abs_time)`.
1269
+
1270
+ *Throws:* Any exception thrown by `pm->try_lock_shared_until(abs_time)`.
1271
+ `system_error` if an exception is required ([[thread.req.exception]]).
1272
+ `system_error` with an error condition of `operation_not_permitted` if
1273
+ `pm` is `nullptr`. `system_error` with an error condition of
1274
+ `resource_deadlock_would_occur` if on entry `owns` is `true`.
1275
+
1276
+ ``` cpp
1277
+ template <class Rep, class Period>
1278
+ bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
1279
+ ```
1280
+
1281
+ *Effects:* `pm->try_lock_shared_for(rel_time)`.
1282
+
1283
+ *Returns:* The value returned by the call to
1284
+ `pm->try_lock_shared_for(rel_time)`.
1285
+
1286
+ *Postconditions:* `owns == res`, where `res` is the value returned by
1287
+ the call to `pm->try_lock_shared_for(rel_time)`.
1288
+
1289
+ *Throws:* Any exception thrown by `pm->try_lock_shared_for(rel_time)`.
1290
+ `system_error` if an exception is required  ([[thread.req.exception]]).
1291
+ `system_error` with an error condition of `operation_not_permitted` if
1292
+ `pm` is `nullptr`. `system_error` with an error condition of
1293
+ `resource_deadlock_would_occur` if on entry `owns` is `true`.
1294
+
1295
+ ``` cpp
1296
+ void unlock();
1297
+ ```
1298
+
1299
+ *Effects:* `pm->unlock_shared()`.
1300
+
1301
+ *Postconditions:* `owns == false`.
1302
+
1303
+ *Throws:* `system_error` when an exception is required
1304
+  ([[thread.req.exception]]).
1305
+
1306
+ *Error conditions:*
1307
+
1308
+ - `operation_not_permitted` — if on entry `owns` is `false`.
1309
+
1310
+ ##### `shared_lock` modifiers <a id="thread.lock.shared.mod">[[thread.lock.shared.mod]]</a>
1311
+
1312
+ ``` cpp
1313
+ void swap(shared_lock& sl) noexcept;
1314
+ ```
1315
+
1316
+ *Effects:* Swaps the data members of `*this` and `sl`.
1317
+
1318
+ ``` cpp
1319
+ mutex_type* release() noexcept;
1320
+ ```
1321
+
1322
+ *Returns:* The previous value of `pm`.
1323
+
1324
+ *Postconditions:* `pm == nullptr` and `owns == false`.
1325
+
1326
+ ``` cpp
1327
+ template <class Mutex>
1328
+ void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
1329
+ ```
1330
+
1331
+ *Effects:* `x.swap(y)`.
1332
+
1333
+ ##### `shared_lock` observers <a id="thread.lock.shared.obs">[[thread.lock.shared.obs]]</a>
1334
+
1335
+ ``` cpp
1336
+ bool owns_lock() const noexcept;
1337
+ ```
1338
+
1339
+ *Returns:* `owns`.
1340
+
1341
+ ``` cpp
1342
+ explicit operator bool () const noexcept;
1343
+ ```
1344
+
1345
+ *Returns:* `owns`.
1346
+
1347
+ ``` cpp
1348
+ mutex_type* mutex() const noexcept;
1349
+ ```
1350
+
1351
+ *Returns:* `pm`.
1352
+
1353
  ### Generic locking algorithms <a id="thread.lock.algorithm">[[thread.lock.algorithm]]</a>
1354
 
1355
  ``` cpp
1356
  template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
1357
  ```
 
1363
  *Effects:* Calls `try_lock()` for each argument in order beginning with
1364
  the first until all arguments have been processed or a call to
1365
  `try_lock()` fails, either by returning `false` or by throwing an
1366
  exception. If a call to `try_lock()` fails, `unlock()` shall be called
1367
  for all prior arguments and there shall be no further calls to
1368
+ `try_lock()`.
1369
 
1370
  *Returns:* `-1` if all calls to `try_lock()` returned `true`, otherwise
1371
  a 0-based index value that indicates the argument for which `try_lock()`
1372
  returned `false`.
1373
 
 
1442
  passive executions.
1443
 
1444
  *Throws:* `system_error` when an exception is
1445
  required ([[thread.req.exception]]), or any exception thrown by `func`.
1446
 
 
 
 
 
1447
  ``` cpp
1448
  // global flag, regular function
1449
  void init();
1450
  std::once_flag flag;
1451