From Jason Turner

[thread.mutex.requirements]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpgs3vzpek/{from.md → to.md} +165 -166
tmp/tmpgs3vzpek/{from.md → to.md} RENAMED
@@ -1,128 +1,129 @@
1
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
2
 
3
  #### In general <a id="thread.mutex.requirements.general">[[thread.mutex.requirements.general]]</a>
4
 
5
  A mutex object facilitates protection against data races and allows safe
6
- synchronization of data between execution agents (
7
- [[thread.req.lockable]]). An execution agent *owns* a mutex from the
8
- time it successfully calls one of the lock functions until it calls
9
- unlock. Mutexes can be either recursive or non-recursive, and can grant
10
  simultaneous ownership to one or many execution agents. Both recursive
11
  and non-recursive mutexes are supplied.
12
 
13
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
14
 
15
  The *mutex types* are the standard library types `mutex`,
16
  `recursive_mutex`, `timed_mutex`, `recursive_timed_mutex`,
17
- `shared_mutex`, and `shared_timed_mutex`. They shall meet the
18
- requirements set out in this section. In this description, `m` denotes
19
- an object of a mutex type.
20
 
21
- The mutex types shall meet the `Lockable` requirements (
22
- [[thread.req.lockable.req]]).
23
 
24
- The mutex types shall be `DefaultConstructible` and `Destructible`. If
25
- initialization of an object of a mutex type fails, an exception of type
26
- `system_error` shall be thrown. The mutex types shall not be copyable or
27
- movable.
28
 
29
  The error conditions for error codes, if any, reported by member
30
- functions of the mutex types shall be:
31
 
32
  - `resource_unavailable_try_again` — if any native handle type
33
  manipulated is not available.
34
  - `operation_not_permitted` — if the thread does not have the privilege
35
  to perform the operation.
36
  - `invalid_argument` — if any native handle type manipulated as part of
37
  mutex construction is incorrect.
38
 
39
- The implementation shall provide lock and unlock operations, as
40
- described below. For purposes of determining the existence of a data
41
- race, these behave as atomic operations ([[intro.multithread]]). The
42
- lock and unlock operations on a single mutex shall appear to occur in a
43
- single total order.
44
 
45
- [*Note 1*: This can be viewed as the modification order (
46
- [[intro.multithread]]) of the mutex. — *end note*]
47
 
48
  [*Note 2*: Construction and destruction of an object of a mutex type
49
  need not be thread-safe; other synchronization should be used to ensure
50
  that mutex objects are initialized and visible to other
51
  threads. — *end note*]
52
 
53
- The expression `m.lock()` shall be well-formed and have the following
54
  semantics:
55
 
56
- *Requires:* If `m` is of type `mutex`, `timed_mutex`, `shared_mutex`, or
57
- `shared_timed_mutex`, the calling thread does not own the mutex.
 
58
 
59
  *Effects:* Blocks the calling thread until ownership of the mutex can be
60
  obtained for the calling thread.
61
 
62
- *Postconditions:* The calling thread owns the mutex.
63
 
64
  *Return type:* `void`.
65
 
66
- *Synchronization:* Prior `unlock()` operations on the same object shall
67
- *synchronize with* ([[intro.multithread]]) this operation.
68
 
69
  *Throws:* `system_error` when an exception is
70
- required ([[thread.req.exception]]).
71
 
72
  *Error conditions:*
73
 
74
  - `operation_not_permitted` — if the thread does not have the privilege
75
  to perform the operation.
76
  - `resource_deadlock_would_occur` — if the implementation detects that a
77
  deadlock would occur.
78
 
79
- The expression `m.try_lock()` shall be well-formed and have the
80
- following semantics:
81
 
82
- *Requires:* If `m` is of type `mutex`, `timed_mutex`, `shared_mutex`, or
83
- `shared_timed_mutex`, the calling thread does not own the mutex.
 
84
 
85
  *Effects:* Attempts to obtain ownership of the mutex for the calling
86
  thread without blocking. If ownership is not obtained, there is no
87
  effect and `try_lock()` immediately returns. An implementation may fail
88
  to obtain the lock even if it is not held by any other thread.
89
 
90
  [*Note 1*: This spurious failure is normally uncommon, but allows
91
- interesting implementations based on a simple compare and exchange
92
- (Clause  [[atomics]]). — *end note*]
93
 
94
  An implementation should ensure that `try_lock()` does not consistently
95
  return `false` in the absence of contending mutex acquisitions.
96
 
97
  *Return type:* `bool`.
98
 
99
  *Returns:* `true` if ownership of the mutex was obtained for the calling
100
  thread, otherwise `false`.
101
 
102
  *Synchronization:* If `try_lock()` returns `true`, prior `unlock()`
103
- operations on the same object *synchronize
104
- with* ([[intro.multithread]]) this operation.
105
 
106
  [*Note 2*: Since `lock()` does not synchronize with a failed subsequent
107
  `try_lock()`, the visibility rules are weak enough that little would be
108
  known about the state after a failure, even in the absence of spurious
109
  failures. — *end note*]
110
 
111
  *Throws:* Nothing.
112
 
113
- The expression `m.unlock()` shall be well-formed and have the following
114
  semantics:
115
 
116
- *Requires:* The calling thread shall own the mutex.
117
 
118
  *Effects:* Releases the calling thread’s ownership of the mutex.
119
 
120
  *Return type:* `void`.
121
 
122
  *Synchronization:* This operation synchronizes
123
- with ([[intro.multithread]]) subsequent lock operations that obtain
124
  ownership on the same object.
125
 
126
  *Throws:* Nothing.
127
 
128
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
@@ -139,12 +140,12 @@ namespace std {
139
 
140
  void lock();
141
  bool try_lock();
142
  void unlock();
143
 
144
- using native_handle_type = implementation-defined; // See~[thread.req.native]
145
- native_handle_type native_handle(); // See~[thread.req.native]
146
  };
147
  }
148
  ```
149
 
150
  The class `mutex` provides a non-recursive mutex with exclusive
@@ -160,17 +161,17 @@ that it is no longer in use, unlock it, and destroy it, before thread
160
  required to handle such scenarios correctly, as long as thread `A`
161
  doesn’t access the mutex after the unlock call returns. These cases
162
  typically occur when a reference-counted object contains a mutex that is
163
  used to protect the reference count. — *end note*]
164
 
165
- The class `mutex` shall satisfy all of the mutex requirements (
166
- [[thread.mutex.requirements]]). It shall be a standard-layout class
167
- (Clause  [[class]]).
168
 
169
- [*Note 4*: A program may deadlock if the thread that owns a `mutex`
170
  object calls `lock()` on that object. If the implementation can detect
171
- the deadlock, a `resource_deadlock_would_occur` error condition may be
172
  observed. — *end note*]
173
 
174
  The behavior of a program is undefined if it destroys a `mutex` object
175
  owned by any thread or a thread terminates while owning a `mutex`
176
  object.
@@ -189,92 +190,92 @@ namespace std {
189
 
190
  void lock();
191
  bool try_lock() noexcept;
192
  void unlock();
193
 
194
- using native_handle_type = implementation-defined; // See~[thread.req.native]
195
- native_handle_type native_handle(); // See~[thread.req.native]
196
  };
197
  }
198
  ```
199
 
200
  The class `recursive_mutex` provides a recursive mutex with exclusive
201
  ownership semantics. If one thread owns a `recursive_mutex` object,
202
  attempts by another thread to acquire ownership of that object will fail
203
  (for `try_lock()`) or block (for `lock()`) until the first thread has
204
  completely released ownership.
205
 
206
- The class `recursive_mutex` shall satisfy all of the mutex
207
- requirements ([[thread.mutex.requirements]]). It shall be a
208
- standard-layout class (Clause  [[class]]).
209
 
210
  A thread that owns a `recursive_mutex` object may acquire additional
211
  levels of ownership by calling `lock()` or `try_lock()` on that object.
212
  It is unspecified how many levels of ownership may be acquired by a
213
  single thread. If a thread has already acquired the maximum level of
214
  ownership for a `recursive_mutex` object, additional calls to
215
- `try_lock()` shall fail, and additional calls to `lock()` shall throw an
216
- exception of type `system_error`. A thread shall call `unlock()` once
217
- for each level of ownership acquired by calls to `lock()` and
218
- `try_lock()`. Only when all levels of ownership have been released may
219
- ownership be acquired by another thread.
220
 
221
  The behavior of a program is undefined if:
222
 
223
  - it destroys a `recursive_mutex` object owned by any thread or
224
  - a thread terminates while owning a `recursive_mutex` object.
225
 
226
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
227
 
228
  The *timed mutex types* are the standard library types `timed_mutex`,
229
- `recursive_timed_mutex`, and `shared_timed_mutex`. They shall meet the
230
  requirements set out below. In this description, `m` denotes an object
231
  of a mutex type, `rel_time` denotes an object of an instantiation of
232
- `duration` ([[time.duration]]), and `abs_time` denotes an object of an
233
- instantiation of `time_point` ([[time.point]]).
234
 
235
- The timed mutex types shall meet the `TimedLockable` requirements (
236
- [[thread.req.lockable.timed]]).
237
 
238
- The expression `m.try_lock_for(rel_time)` shall be well-formed and have
239
- the following semantics:
240
 
241
- *Requires:* If `m` is of type `timed_mutex` or `shared_timed_mutex`, the
242
- calling thread does not own the mutex.
243
 
244
  *Effects:* The function attempts to obtain ownership of the mutex within
245
- the relative timeout ([[thread.req.timing]]) specified by `rel_time`.
246
- If the time specified by `rel_time` is less than or equal to
247
  `rel_time.zero()`, the function attempts to obtain ownership without
248
- blocking (as if by calling `try_lock()`). The function shall return
249
- within the timeout specified by `rel_time` only if it has obtained
250
- ownership of the mutex object.
251
 
252
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
253
  will be obtained if the lock is available, but implementations are
254
  expected to make a strong effort to do so. — *end note*]
255
 
256
  *Return type:* `bool`.
257
 
258
  *Returns:* `true` if ownership was obtained, otherwise `false`.
259
 
260
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
261
- operations on the same object *synchronize
262
- with* ([[intro.multithread]]) this operation.
263
 
264
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
265
 
266
- The expression `m.try_lock_until(abs_time)` shall be well-formed and
267
- have the following semantics:
268
 
269
- *Requires:* If `m` is of type `timed_mutex` or `shared_timed_mutex`, the
270
- calling thread does not own the mutex.
271
 
272
  *Effects:* The function attempts to obtain ownership of the mutex. If
273
  `abs_time` has already passed, the function attempts to obtain ownership
274
- without blocking (as if by calling `try_lock()`). The function shall
275
- return before the absolute timeout ([[thread.req.timing]]) specified by
276
  `abs_time` only if it has obtained ownership of the mutex object.
277
 
278
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
279
  will be obtained if the lock is available, but implementations are
280
  expected to make a strong effort to do so. — *end note*]
@@ -283,13 +284,13 @@ expected to make a strong effort to do so. — *end note*]
283
 
284
  *Returns:* `true` if ownership was obtained, otherwise `false`.
285
 
286
  *Synchronization:* If `try_lock_until()` returns `true`, prior
287
  `unlock()` operations on the same object *synchronize
288
- with* ([[intro.multithread]]) this operation.
289
 
290
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
291
 
292
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
293
 
294
  ``` cpp
295
  namespace std {
@@ -307,12 +308,12 @@ namespace std {
307
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
308
  template<class Clock, class Duration>
309
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
310
  void unlock();
311
 
312
- using native_handle_type = implementation-defined; // See~[thread.req.native]
313
- native_handle_type native_handle(); // See~[thread.req.native]
314
  };
315
  }
316
  ```
317
 
318
  The class `timed_mutex` provides a non-recursive mutex with exclusive
@@ -321,13 +322,13 @@ by another thread to acquire ownership of that object will fail (for
321
  `try_lock()`) or block (for `lock()`, `try_lock_for()`, and
322
  `try_lock_until()`) until the owning thread has released ownership with
323
  a call to `unlock()` or the call to `try_lock_for()` or
324
  `try_lock_until()` times out (having failed to obtain ownership).
325
 
326
- The class `timed_mutex` shall satisfy all of the timed mutex
327
- requirements ([[thread.timedmutex.requirements]]). It shall be a
328
- standard-layout class (Clause  [[class]]).
329
 
330
  The behavior of a program is undefined if:
331
 
332
  - it destroys a `timed_mutex` object owned by any thread,
333
  - a thread that owns a `timed_mutex` object calls `lock()`,
@@ -353,12 +354,12 @@ namespace std {
353
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
354
  template<class Clock, class Duration>
355
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
356
  void unlock();
357
 
358
- using native_handle_type = implementation-defined; // See~[thread.req.native]
359
- native_handle_type native_handle(); // See~[thread.req.native]
360
  };
361
  }
362
  ```
363
 
364
  The class `recursive_timed_mutex` provides a recursive mutex with
@@ -367,99 +368,99 @@ exclusive ownership semantics. If one thread owns a
367
  ownership of that object will fail (for `try_lock()`) or block (for
368
  `lock()`, `try_lock_for()`, and `try_lock_until()`) until the owning
369
  thread has completely released ownership or the call to `try_lock_for()`
370
  or `try_lock_until()` times out (having failed to obtain ownership).
371
 
372
- The class `recursive_timed_mutex` shall satisfy all of the timed mutex
373
- requirements ([[thread.timedmutex.requirements]]). It shall be a
374
- standard-layout class (Clause  [[class]]).
375
 
376
  A thread that owns a `recursive_timed_mutex` object may acquire
377
  additional levels of ownership by calling `lock()`, `try_lock()`,
378
  `try_lock_for()`, or `try_lock_until()` on that object. It is
379
  unspecified how many levels of ownership may be acquired by a single
380
  thread. If a thread has already acquired the maximum level of ownership
381
  for a `recursive_timed_mutex` object, additional calls to `try_lock()`,
382
- `try_lock_for()`, or `try_lock_until()` shall fail, and additional calls
383
- to `lock()` shall throw an exception of type `system_error`. A thread
384
- shall call `unlock()` once for each level of ownership acquired by calls
385
- to `lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`.
386
- Only when all levels of ownership have been released may ownership of
387
- the object be acquired by another thread.
388
 
389
  The behavior of a program is undefined if:
390
 
391
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
392
  - a thread terminates while owning a `recursive_timed_mutex` object.
393
 
394
  #### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
395
 
396
  The standard library types `shared_mutex` and `shared_timed_mutex` are
397
- *shared mutex types*. Shared mutex types shall meet the requirements of
398
- mutex types ([[thread.mutex.requirements.mutex]]), and additionally
399
- shall meet the requirements set out below. In this description, `m`
400
- denotes an object of a shared mutex type.
401
 
402
  In addition to the exclusive lock ownership mode specified in 
403
  [[thread.mutex.requirements.mutex]], shared mutex types provide a
404
  *shared lock* ownership mode. Multiple execution agents can
405
  simultaneously hold a shared lock ownership of a shared mutex type. But
406
- no execution agent shall hold a shared lock while another execution
407
- agent holds an exclusive lock on the same shared mutex type, and
408
- vice-versa. The maximum number of execution agents which can share a
409
- shared lock on a single shared mutex type is unspecified, but shall be
410
- at least 10000. If more than the maximum number of execution agents
411
- attempt to obtain a shared lock, the excess execution agents shall block
412
- until the number of shared locks are reduced below the maximum amount by
413
- other execution agents releasing their shared lock.
414
 
415
- The expression `m.lock_shared()` shall be well-formed and have the
416
- following semantics:
417
 
418
- *Requires:* The calling thread has no ownership of the mutex.
419
 
420
  *Effects:* Blocks the calling thread until shared ownership of the mutex
421
  can be obtained for the calling thread. If an exception is thrown then a
422
- shared lock shall not have been acquired for the current thread.
423
 
424
- *Postconditions:* The calling thread has a shared lock on the mutex.
425
 
426
  *Return type:* `void`.
427
 
428
- *Synchronization:* Prior `unlock()` operations on the same object shall
429
- synchronize with ([[intro.multithread]]) this operation.
430
 
431
  *Throws:* `system_error` when an exception is
432
- required ([[thread.req.exception]]).
433
 
434
  *Error conditions:*
435
 
436
  - `operation_not_permitted` — if the thread does not have the privilege
437
  to perform the operation.
438
  - `resource_deadlock_would_occur` — if the implementation detects that a
439
  deadlock would occur.
440
 
441
- The expression `m.unlock_shared()` shall be well-formed and have the
442
- following semantics:
443
 
444
- *Requires:* The calling thread shall hold a shared lock on the mutex.
445
 
446
  *Effects:* Releases a shared lock on the mutex held by the calling
447
  thread.
448
 
449
  *Return type:* `void`.
450
 
451
  *Synchronization:* This operation synchronizes
452
- with ([[intro.multithread]]) subsequent `lock()` operations that obtain
453
  ownership on the same object.
454
 
455
  *Throws:* Nothing.
456
 
457
- The expression `m.try_lock_shared()` shall be well-formed and have the
458
  following semantics:
459
 
460
- *Requires:* The calling thread has no ownership of the mutex.
461
 
462
  *Effects:* Attempts to obtain shared ownership of the mutex for the
463
  calling thread without blocking. If shared ownership is not obtained,
464
  there is no effect and `try_lock_shared()` immediately returns. An
465
  implementation may fail to obtain the lock even if it is not held by any
@@ -470,15 +471,15 @@ other thread.
470
  *Returns:* `true` if the shared ownership lock was acquired, `false`
471
  otherwise.
472
 
473
  *Synchronization:* If `try_lock_shared()` returns `true`, prior
474
  `unlock()` operations on the same object synchronize
475
- with ([[intro.multithread]]) this operation.
476
 
477
  *Throws:* Nothing.
478
 
479
- ##### Class shared_mutex <a id="thread.sharedmutex.class">[[thread.sharedmutex.class]]</a>
480
 
481
  ``` cpp
482
  namespace std {
483
  class shared_mutex {
484
  public:
@@ -486,32 +487,32 @@ namespace std {
486
  ~shared_mutex();
487
 
488
  shared_mutex(const shared_mutex&) = delete;
489
  shared_mutex& operator=(const shared_mutex&) = delete;
490
 
491
- // Exclusive ownership
492
  void lock(); // blocking
493
  bool try_lock();
494
  void unlock();
495
 
496
- // Shared ownership
497
  void lock_shared(); // blocking
498
  bool try_lock_shared();
499
  void unlock_shared();
500
 
501
- using native_handle_type = implementation-defined; // See~[thread.req.native]
502
- native_handle_type native_handle(); // See~[thread.req.native]
503
  };
504
  }
505
  ```
506
 
507
  The class `shared_mutex` provides a non-recursive mutex with shared
508
  ownership semantics.
509
 
510
- The class `shared_mutex` shall satisfy all of the shared mutex
511
- requirements ([[thread.sharedmutex.requirements]]). It shall be a
512
- standard-layout class (Clause  [[class]]).
513
 
514
  The behavior of a program is undefined if:
515
 
516
  - it destroys a `shared_mutex` object owned by any thread,
517
  - a thread attempts to recursively gain any ownership of a
@@ -522,76 +523,76 @@ The behavior of a program is undefined if:
522
  `shared_mutex` may be a synonym for `shared_timed_mutex`.
523
 
524
  #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
525
 
526
  The standard library type `shared_timed_mutex` is a *shared timed mutex
527
- type*. Shared timed mutex types shall meet the requirements of timed
528
- mutex types ([[thread.timedmutex.requirements]]), shared mutex types (
529
- [[thread.sharedmutex.requirements]]), and additionally shall meet the
530
  requirements set out below. In this description, `m` denotes an object
531
  of a shared timed mutex type, `rel_type` denotes an object of an
532
- instantiation of `duration` ([[time.duration]]), and `abs_time` denotes
533
- an object of an instantiation of `time_point` ([[time.point]]).
534
 
535
- The expression `m.try_lock_shared_for(rel_time)` shall be well-formed
536
- and have the following semantics:
537
 
538
- *Requires:* The calling thread has no ownership of the mutex.
539
 
540
  *Effects:* Attempts to obtain shared lock ownership for the calling
541
- thread within the relative timeout ([[thread.req.timing]]) specified by
542
  `rel_time`. If the time specified by `rel_time` is less than or equal to
543
  `rel_time.zero()`, the function attempts to obtain ownership without
544
- blocking (as if by calling `try_lock_shared()`). The function shall
545
- return within the timeout specified by `rel_time` only if it has
546
- obtained shared ownership of the mutex object.
547
 
548
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
549
  will be obtained if the lock is available, but implementations are
550
  expected to make a strong effort to do so. — *end note*]
551
 
552
- If an exception is thrown then a shared lock shall not have been
553
- acquired for the current thread.
554
 
555
  *Return type:* `bool`.
556
 
557
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
558
 
559
  *Synchronization:* If `try_lock_shared_for()` returns `true`, prior
560
  `unlock()` operations on the same object synchronize
561
- with ([[intro.multithread]]) this operation.
562
 
563
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
564
 
565
- The expression `m.try_lock_shared_until(abs_time)` shall be well-formed
566
- and have the following semantics:
567
 
568
- *Requires:* The calling thread has no ownership of the mutex.
569
 
570
  *Effects:* The function attempts to obtain shared ownership of the
571
  mutex. If `abs_time` has already passed, the function attempts to obtain
572
  shared ownership without blocking (as if by calling
573
- `try_lock_shared()`). The function shall return before the absolute
574
- timeout ([[thread.req.timing]]) specified by `abs_time` only if it has
575
  obtained shared ownership of the mutex object.
576
 
577
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
578
  will be obtained if the lock is available, but implementations are
579
  expected to make a strong effort to do so. — *end note*]
580
 
581
- If an exception is thrown then a shared lock shall not have been
582
- acquired for the current thread.
583
 
584
  *Return type:* `bool`.
585
 
586
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
587
 
588
  *Synchronization:* If `try_lock_shared_until()` returns `true`, prior
589
  `unlock()` operations on the same object synchronize
590
- with ([[intro.multithread]]) this operation.
591
 
592
- *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
593
 
594
  ##### Class `shared_timed_mutex` <a id="thread.sharedtimedmutex.class">[[thread.sharedtimedmutex.class]]</a>
595
 
596
  ``` cpp
597
  namespace std {
@@ -601,39 +602,37 @@ namespace std {
601
  ~shared_timed_mutex();
602
 
603
  shared_timed_mutex(const shared_timed_mutex&) = delete;
604
  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
605
 
606
- // Exclusive ownership
607
  void lock(); // blocking
608
  bool try_lock();
609
  template<class Rep, class Period>
610
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
611
  template<class Clock, class Duration>
612
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
613
  void unlock();
614
 
615
- // Shared ownership
616
  void lock_shared(); // blocking
617
  bool try_lock_shared();
618
  template<class Rep, class Period>
619
- bool
620
- try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
621
  template<class Clock, class Duration>
622
- bool
623
- try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
624
  void unlock_shared();
625
  };
626
  }
627
  ```
628
 
629
  The class `shared_timed_mutex` provides a non-recursive mutex with
630
  shared ownership semantics.
631
 
632
- The class `shared_timed_mutex` shall satisfy all of the shared timed
633
- mutex requirements ([[thread.sharedtimedmutex.requirements]]). It shall
634
- be a standard-layout class (Clause  [[class]]).
635
 
636
  The behavior of a program is undefined if:
637
 
638
  - it destroys a `shared_timed_mutex` object owned by any thread,
639
  - a thread attempts to recursively gain any ownership of a
 
1
  ### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
2
 
3
  #### In general <a id="thread.mutex.requirements.general">[[thread.mutex.requirements.general]]</a>
4
 
5
  A mutex object facilitates protection against data races and allows safe
6
+ synchronization of data between execution agents
7
+ [[thread.req.lockable]]. An execution agent *owns* a mutex from the time
8
+ it successfully calls one of the lock functions until it calls unlock.
9
+ Mutexes can be either recursive or non-recursive, and can grant
10
  simultaneous ownership to one or many execution agents. Both recursive
11
  and non-recursive mutexes are supplied.
12
 
13
  #### Mutex types <a id="thread.mutex.requirements.mutex">[[thread.mutex.requirements.mutex]]</a>
14
 
15
  The *mutex types* are the standard library types `mutex`,
16
  `recursive_mutex`, `timed_mutex`, `recursive_timed_mutex`,
17
+ `shared_mutex`, and `shared_timed_mutex`. They meet the requirements set
18
+ out in this subclause. In this description, `m` denotes an object of a
19
+ mutex type.
20
 
21
+ The mutex types meet the *Cpp17Lockable* requirements
22
+ [[thread.req.lockable.req]].
23
 
24
+ The mutex types meet *Cpp17DefaultConstructible* and
25
+ *Cpp17Destructible*. If initialization of an object of a mutex type
26
+ fails, an exception of type `system_error` is thrown. The mutex types
27
+ are neither copyable nor movable.
28
 
29
  The error conditions for error codes, if any, reported by member
30
+ functions of the mutex types are as follows:
31
 
32
  - `resource_unavailable_try_again` — if any native handle type
33
  manipulated is not available.
34
  - `operation_not_permitted` — if the thread does not have the privilege
35
  to perform the operation.
36
  - `invalid_argument` — if any native handle type manipulated as part of
37
  mutex construction is incorrect.
38
 
39
+ The implementation provides lock and unlock operations, as described
40
+ below. For purposes of determining the existence of a data race, these
41
+ behave as atomic operations [[intro.multithread]]. The lock and unlock
42
+ operations on a single mutex appears to occur in a single total order.
 
43
 
44
+ [*Note 1*: This can be viewed as the modification order
45
+ [[intro.multithread]] of the mutex. — *end note*]
46
 
47
  [*Note 2*: Construction and destruction of an object of a mutex type
48
  need not be thread-safe; other synchronization should be used to ensure
49
  that mutex objects are initialized and visible to other
50
  threads. — *end note*]
51
 
52
+ The expression `m.lock()` is well-formed and has the following
53
  semantics:
54
 
55
+ *Preconditions:* If `m` is of type `mutex`, `timed_mutex`,
56
+ `shared_mutex`, or `shared_timed_mutex`, the calling thread does not own
57
+ the mutex.
58
 
59
  *Effects:* Blocks the calling thread until ownership of the mutex can be
60
  obtained for the calling thread.
61
 
62
+ *Ensures:* The calling thread owns the mutex.
63
 
64
  *Return type:* `void`.
65
 
66
+ *Synchronization:* Prior `unlock()` operations on the same object
67
+ *synchronize with*[[intro.multithread]] this operation.
68
 
69
  *Throws:* `system_error` when an exception is
70
+ required [[thread.req.exception]].
71
 
72
  *Error conditions:*
73
 
74
  - `operation_not_permitted` — if the thread does not have the privilege
75
  to perform the operation.
76
  - `resource_deadlock_would_occur` — if the implementation detects that a
77
  deadlock would occur.
78
 
79
+ The expression `m.try_lock()` is well-formed and has the following
80
+ semantics:
81
 
82
+ *Preconditions:* If `m` is of type `mutex`, `timed_mutex`,
83
+ `shared_mutex`, or `shared_timed_mutex`, the calling thread does not own
84
+ the mutex.
85
 
86
  *Effects:* Attempts to obtain ownership of the mutex for the calling
87
  thread without blocking. If ownership is not obtained, there is no
88
  effect and `try_lock()` immediately returns. An implementation may fail
89
  to obtain the lock even if it is not held by any other thread.
90
 
91
  [*Note 1*: This spurious failure is normally uncommon, but allows
92
+ interesting implementations based on a simple compare and
93
+ exchange [[atomics]]. — *end note*]
94
 
95
  An implementation should ensure that `try_lock()` does not consistently
96
  return `false` in the absence of contending mutex acquisitions.
97
 
98
  *Return type:* `bool`.
99
 
100
  *Returns:* `true` if ownership of the mutex was obtained for the calling
101
  thread, otherwise `false`.
102
 
103
  *Synchronization:* If `try_lock()` returns `true`, prior `unlock()`
104
+ operations on the same object *synchronize with*[[intro.multithread]]
105
+ this operation.
106
 
107
  [*Note 2*: Since `lock()` does not synchronize with a failed subsequent
108
  `try_lock()`, the visibility rules are weak enough that little would be
109
  known about the state after a failure, even in the absence of spurious
110
  failures. — *end note*]
111
 
112
  *Throws:* Nothing.
113
 
114
+ The expression `m.unlock()` is well-formed and has the following
115
  semantics:
116
 
117
+ *Preconditions:* The calling thread owns the mutex.
118
 
119
  *Effects:* Releases the calling thread’s ownership of the mutex.
120
 
121
  *Return type:* `void`.
122
 
123
  *Synchronization:* This operation synchronizes
124
+ with [[intro.multithread]] subsequent lock operations that obtain
125
  ownership on the same object.
126
 
127
  *Throws:* Nothing.
128
 
129
  ##### Class `mutex` <a id="thread.mutex.class">[[thread.mutex.class]]</a>
 
140
 
141
  void lock();
142
  bool try_lock();
143
  void unlock();
144
 
145
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
146
+ native_handle_type native_handle(); // see~[thread.req.native]
147
  };
148
  }
149
  ```
150
 
151
  The class `mutex` provides a non-recursive mutex with exclusive
 
161
  required to handle such scenarios correctly, as long as thread `A`
162
  doesn’t access the mutex after the unlock call returns. These cases
163
  typically occur when a reference-counted object contains a mutex that is
164
  used to protect the reference count. — *end note*]
165
 
166
+ The class `mutex` meets all of the mutex requirements
167
+ [[thread.mutex.requirements]]. It is a standard-layout class
168
+ [[class.prop]].
169
 
170
+ [*Note 4*: A program can deadlock if the thread that owns a `mutex`
171
  object calls `lock()` on that object. If the implementation can detect
172
+ the deadlock, a `resource_deadlock_would_occur` error condition might be
173
  observed. — *end note*]
174
 
175
  The behavior of a program is undefined if it destroys a `mutex` object
176
  owned by any thread or a thread terminates while owning a `mutex`
177
  object.
 
190
 
191
  void lock();
192
  bool try_lock() noexcept;
193
  void unlock();
194
 
195
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
196
+ native_handle_type native_handle(); // see~[thread.req.native]
197
  };
198
  }
199
  ```
200
 
201
  The class `recursive_mutex` provides a recursive mutex with exclusive
202
  ownership semantics. If one thread owns a `recursive_mutex` object,
203
  attempts by another thread to acquire ownership of that object will fail
204
  (for `try_lock()`) or block (for `lock()`) until the first thread has
205
  completely released ownership.
206
 
207
+ The class `recursive_mutex` meets all of the mutex requirements
208
+ [[thread.mutex.requirements]]. It is a standard-layout class
209
+ [[class.prop]].
210
 
211
  A thread that owns a `recursive_mutex` object may acquire additional
212
  levels of ownership by calling `lock()` or `try_lock()` on that object.
213
  It is unspecified how many levels of ownership may be acquired by a
214
  single thread. If a thread has already acquired the maximum level of
215
  ownership for a `recursive_mutex` object, additional calls to
216
+ `try_lock()` fail, and additional calls to `lock()` throw an exception
217
+ of type `system_error`. A thread shall call `unlock()` once for each
218
+ level of ownership acquired by calls to `lock()` and `try_lock()`. Only
219
+ when all levels of ownership have been released may ownership be
220
+ acquired by another thread.
221
 
222
  The behavior of a program is undefined if:
223
 
224
  - it destroys a `recursive_mutex` object owned by any thread or
225
  - a thread terminates while owning a `recursive_mutex` object.
226
 
227
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
228
 
229
  The *timed mutex types* are the standard library types `timed_mutex`,
230
+ `recursive_timed_mutex`, and `shared_timed_mutex`. They meet the
231
  requirements set out below. In this description, `m` denotes an object
232
  of a mutex type, `rel_time` denotes an object of an instantiation of
233
+ `duration` [[time.duration]], and `abs_time` denotes an object of an
234
+ instantiation of `time_point` [[time.point]].
235
 
236
+ The timed mutex types meet the *Cpp17TimedLockable* requirements
237
+ [[thread.req.lockable.timed]].
238
 
239
+ The expression `m.try_lock_for(rel_time)` is well-formed and has the
240
+ following semantics:
241
 
242
+ *Preconditions:* If `m` is of type `timed_mutex` or
243
+ `shared_timed_mutex`, the calling thread does not own the mutex.
244
 
245
  *Effects:* The function attempts to obtain ownership of the mutex within
246
+ the relative timeout [[thread.req.timing]] specified by `rel_time`. If
247
+ the time specified by `rel_time` is less than or equal to
248
  `rel_time.zero()`, the function attempts to obtain ownership without
249
+ blocking (as if by calling `try_lock()`). The function returns within
250
+ the timeout specified by `rel_time` only if it has obtained ownership of
251
+ the mutex object.
252
 
253
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
254
  will be obtained if the lock is available, but implementations are
255
  expected to make a strong effort to do so. — *end note*]
256
 
257
  *Return type:* `bool`.
258
 
259
  *Returns:* `true` if ownership was obtained, otherwise `false`.
260
 
261
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
262
+ operations on the same object *synchronize with*[[intro.multithread]]
263
+ this operation.
264
 
265
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
266
 
267
+ The expression `m.try_lock_until(abs_time)` is well-formed and has the
268
+ following semantics:
269
 
270
+ *Preconditions:* If `m` is of type `timed_mutex` or
271
+ `shared_timed_mutex`, the calling thread does not own the mutex.
272
 
273
  *Effects:* The function attempts to obtain ownership of the mutex. If
274
  `abs_time` has already passed, the function attempts to obtain ownership
275
+ without blocking (as if by calling `try_lock()`). The function returns
276
+ before the absolute timeout [[thread.req.timing]] specified by
277
  `abs_time` only if it has obtained ownership of the mutex object.
278
 
279
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
280
  will be obtained if the lock is available, but implementations are
281
  expected to make a strong effort to do so. — *end note*]
 
284
 
285
  *Returns:* `true` if ownership was obtained, otherwise `false`.
286
 
287
  *Synchronization:* If `try_lock_until()` returns `true`, prior
288
  `unlock()` operations on the same object *synchronize
289
+ with*[[intro.multithread]] this operation.
290
 
291
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
292
 
293
  ##### Class `timed_mutex` <a id="thread.timedmutex.class">[[thread.timedmutex.class]]</a>
294
 
295
  ``` cpp
296
  namespace std {
 
308
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
309
  template<class Clock, class Duration>
310
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
311
  void unlock();
312
 
313
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
314
+ native_handle_type native_handle(); // see~[thread.req.native]
315
  };
316
  }
317
  ```
318
 
319
  The class `timed_mutex` provides a non-recursive mutex with exclusive
 
322
  `try_lock()`) or block (for `lock()`, `try_lock_for()`, and
323
  `try_lock_until()`) until the owning thread has released ownership with
324
  a call to `unlock()` or the call to `try_lock_for()` or
325
  `try_lock_until()` times out (having failed to obtain ownership).
326
 
327
+ The class `timed_mutex` meets all of the timed mutex requirements
328
+ [[thread.timedmutex.requirements]]. It is a standard-layout class
329
+ [[class.prop]].
330
 
331
  The behavior of a program is undefined if:
332
 
333
  - it destroys a `timed_mutex` object owned by any thread,
334
  - a thread that owns a `timed_mutex` object calls `lock()`,
 
354
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
355
  template<class Clock, class Duration>
356
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
357
  void unlock();
358
 
359
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
360
+ native_handle_type native_handle(); // see~[thread.req.native]
361
  };
362
  }
363
  ```
364
 
365
  The class `recursive_timed_mutex` provides a recursive mutex with
 
368
  ownership of that object will fail (for `try_lock()`) or block (for
369
  `lock()`, `try_lock_for()`, and `try_lock_until()`) until the owning
370
  thread has completely released ownership or the call to `try_lock_for()`
371
  or `try_lock_until()` times out (having failed to obtain ownership).
372
 
373
+ The class `recursive_timed_mutex` meets all of the timed mutex
374
+ requirements [[thread.timedmutex.requirements]]. It is a standard-layout
375
+ class [[class.prop]].
376
 
377
  A thread that owns a `recursive_timed_mutex` object may acquire
378
  additional levels of ownership by calling `lock()`, `try_lock()`,
379
  `try_lock_for()`, or `try_lock_until()` on that object. It is
380
  unspecified how many levels of ownership may be acquired by a single
381
  thread. If a thread has already acquired the maximum level of ownership
382
  for a `recursive_timed_mutex` object, additional calls to `try_lock()`,
383
+ `try_lock_for()`, or `try_lock_until()` fail, and additional calls to
384
+ `lock()` throw an exception of type `system_error`. A thread shall call
385
+ `unlock()` once for each level of ownership acquired by calls to
386
+ `lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`. Only
387
+ when all levels of ownership have been released may ownership of the
388
+ object be acquired by another thread.
389
 
390
  The behavior of a program is undefined if:
391
 
392
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
393
  - a thread terminates while owning a `recursive_timed_mutex` object.
394
 
395
  #### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
396
 
397
  The standard library types `shared_mutex` and `shared_timed_mutex` are
398
+ *shared mutex types*. Shared mutex types meet the requirements of mutex
399
+ types [[thread.mutex.requirements.mutex]] and additionally meet the
400
+ requirements set out below. In this description, `m` denotes an object
401
+ of a shared mutex type.
402
 
403
  In addition to the exclusive lock ownership mode specified in 
404
  [[thread.mutex.requirements.mutex]], shared mutex types provide a
405
  *shared lock* ownership mode. Multiple execution agents can
406
  simultaneously hold a shared lock ownership of a shared mutex type. But
407
+ no execution agent holds a shared lock while another execution agent
408
+ holds an exclusive lock on the same shared mutex type, and vice-versa.
409
+ The maximum number of execution agents which can share a shared lock on
410
+ a single shared mutex type is unspecified, but is at least 10000. If
411
+ more than the maximum number of execution agents attempt to obtain a
412
+ shared lock, the excess execution agents block until the number of
413
+ shared locks are reduced below the maximum amount by other execution
414
+ agents releasing their shared lock.
415
 
416
+ The expression `m.lock_shared()` is well-formed and has the following
417
+ semantics:
418
 
419
+ *Preconditions:* The calling thread has no ownership of the mutex.
420
 
421
  *Effects:* Blocks the calling thread until shared ownership of the mutex
422
  can be obtained for the calling thread. If an exception is thrown then a
423
+ shared lock has not been acquired for the current thread.
424
 
425
+ *Ensures:* The calling thread has a shared lock on the mutex.
426
 
427
  *Return type:* `void`.
428
 
429
+ *Synchronization:* Prior `unlock()` operations on the same object
430
+ synchronize with [[intro.multithread]] this operation.
431
 
432
  *Throws:* `system_error` when an exception is
433
+ required [[thread.req.exception]].
434
 
435
  *Error conditions:*
436
 
437
  - `operation_not_permitted` — if the thread does not have the privilege
438
  to perform the operation.
439
  - `resource_deadlock_would_occur` — if the implementation detects that a
440
  deadlock would occur.
441
 
442
+ The expression `m.unlock_shared()` is well-formed and has the following
443
+ semantics:
444
 
445
+ *Preconditions:* The calling thread holds a shared lock on the mutex.
446
 
447
  *Effects:* Releases a shared lock on the mutex held by the calling
448
  thread.
449
 
450
  *Return type:* `void`.
451
 
452
  *Synchronization:* This operation synchronizes
453
+ with [[intro.multithread]] subsequent `lock()` operations that obtain
454
  ownership on the same object.
455
 
456
  *Throws:* Nothing.
457
 
458
+ The expression `m.try_lock_shared()` is well-formed and has the
459
  following semantics:
460
 
461
+ *Preconditions:* The calling thread has no ownership of the mutex.
462
 
463
  *Effects:* Attempts to obtain shared ownership of the mutex for the
464
  calling thread without blocking. If shared ownership is not obtained,
465
  there is no effect and `try_lock_shared()` immediately returns. An
466
  implementation may fail to obtain the lock even if it is not held by any
 
471
  *Returns:* `true` if the shared ownership lock was acquired, `false`
472
  otherwise.
473
 
474
  *Synchronization:* If `try_lock_shared()` returns `true`, prior
475
  `unlock()` operations on the same object synchronize
476
+ with [[intro.multithread]] this operation.
477
 
478
  *Throws:* Nothing.
479
 
480
+ ##### Class `shared_mutex` <a id="thread.sharedmutex.class">[[thread.sharedmutex.class]]</a>
481
 
482
  ``` cpp
483
  namespace std {
484
  class shared_mutex {
485
  public:
 
487
  ~shared_mutex();
488
 
489
  shared_mutex(const shared_mutex&) = delete;
490
  shared_mutex& operator=(const shared_mutex&) = delete;
491
 
492
+ // exclusive ownership
493
  void lock(); // blocking
494
  bool try_lock();
495
  void unlock();
496
 
497
+ // shared ownership
498
  void lock_shared(); // blocking
499
  bool try_lock_shared();
500
  void unlock_shared();
501
 
502
+ using native_handle_type = implementation-defined; // see~[thread.req.native]
503
+ native_handle_type native_handle(); // see~[thread.req.native]
504
  };
505
  }
506
  ```
507
 
508
  The class `shared_mutex` provides a non-recursive mutex with shared
509
  ownership semantics.
510
 
511
+ The class `shared_mutex` meets all of the shared mutex requirements
512
+ [[thread.sharedmutex.requirements]]. It is a standard-layout class
513
+ [[class.prop]].
514
 
515
  The behavior of a program is undefined if:
516
 
517
  - it destroys a `shared_mutex` object owned by any thread,
518
  - a thread attempts to recursively gain any ownership of a
 
523
  `shared_mutex` may be a synonym for `shared_timed_mutex`.
524
 
525
  #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
526
 
527
  The standard library type `shared_timed_mutex` is a *shared timed mutex
528
+ type*. Shared timed mutex types meet the requirements of timed mutex
529
+ types [[thread.timedmutex.requirements]], shared mutex types
530
+ [[thread.sharedmutex.requirements]], and additionally meet the
531
  requirements set out below. In this description, `m` denotes an object
532
  of a shared timed mutex type, `rel_type` denotes an object of an
533
+ instantiation of `duration` [[time.duration]], and `abs_time` denotes an
534
+ object of an instantiation of `time_point` [[time.point]].
535
 
536
+ The expression `m.try_lock_shared_for(rel_time)` is well-formed and has
537
+ the following semantics:
538
 
539
+ *Preconditions:* The calling thread has no ownership of the mutex.
540
 
541
  *Effects:* Attempts to obtain shared lock ownership for the calling
542
+ thread within the relative timeout [[thread.req.timing]] specified by
543
  `rel_time`. If the time specified by `rel_time` is less than or equal to
544
  `rel_time.zero()`, the function attempts to obtain ownership without
545
+ blocking (as if by calling `try_lock_shared()`). The function returns
546
+ within the timeout specified by `rel_time` only if it has obtained
547
+ shared ownership of the mutex object.
548
 
549
  [*Note 1*: As with `try_lock()`, there is no guarantee that ownership
550
  will be obtained if the lock is available, but implementations are
551
  expected to make a strong effort to do so. — *end note*]
552
 
553
+ If an exception is thrown then a shared lock has not been acquired for
554
+ the current thread.
555
 
556
  *Return type:* `bool`.
557
 
558
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
559
 
560
  *Synchronization:* If `try_lock_shared_for()` returns `true`, prior
561
  `unlock()` operations on the same object synchronize
562
+ with [[intro.multithread]] this operation.
563
 
564
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
565
 
566
+ The expression `m.try_lock_shared_until(abs_time)` is well-formed and
567
+ has the following semantics:
568
 
569
+ *Preconditions:* The calling thread has no ownership of the mutex.
570
 
571
  *Effects:* The function attempts to obtain shared ownership of the
572
  mutex. If `abs_time` has already passed, the function attempts to obtain
573
  shared ownership without blocking (as if by calling
574
+ `try_lock_shared()`). The function returns before the absolute
575
+ timeout [[thread.req.timing]] specified by `abs_time` only if it has
576
  obtained shared ownership of the mutex object.
577
 
578
  [*Note 2*: As with `try_lock()`, there is no guarantee that ownership
579
  will be obtained if the lock is available, but implementations are
580
  expected to make a strong effort to do so. — *end note*]
581
 
582
+ If an exception is thrown then a shared lock has not been acquired for
583
+ the current thread.
584
 
585
  *Return type:* `bool`.
586
 
587
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
588
 
589
  *Synchronization:* If `try_lock_shared_until()` returns `true`, prior
590
  `unlock()` operations on the same object synchronize
591
+ with [[intro.multithread]] this operation.
592
 
593
+ *Throws:* Timeout-related exceptions [[thread.req.timing]].
594
 
595
  ##### Class `shared_timed_mutex` <a id="thread.sharedtimedmutex.class">[[thread.sharedtimedmutex.class]]</a>
596
 
597
  ``` cpp
598
  namespace std {
 
602
  ~shared_timed_mutex();
603
 
604
  shared_timed_mutex(const shared_timed_mutex&) = delete;
605
  shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
606
 
607
+ // exclusive ownership
608
  void lock(); // blocking
609
  bool try_lock();
610
  template<class Rep, class Period>
611
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
612
  template<class Clock, class Duration>
613
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
614
  void unlock();
615
 
616
+ // shared ownership
617
  void lock_shared(); // blocking
618
  bool try_lock_shared();
619
  template<class Rep, class Period>
620
+ bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
 
621
  template<class Clock, class Duration>
622
+ bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
 
623
  void unlock_shared();
624
  };
625
  }
626
  ```
627
 
628
  The class `shared_timed_mutex` provides a non-recursive mutex with
629
  shared ownership semantics.
630
 
631
+ The class `shared_timed_mutex` meets all of the shared timed mutex
632
+ requirements [[thread.sharedtimedmutex.requirements]]. It is a
633
+ standard-layout class [[class.prop]].
634
 
635
  The behavior of a program is undefined if:
636
 
637
  - it destroys a `shared_timed_mutex` object owned by any thread,
638
  - a thread attempts to recursively gain any ownership of a