From Jason Turner

[thread.mutex.requirements]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp1m8hwszj/{from.md → to.md} +161 -98
tmp/tmp1m8hwszj/{from.md → to.md} RENAMED
@@ -10,15 +10,15 @@ 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 `std::mutex`,
16
- `std::recursive_mutex`, `std::timed_mutex`,
17
- `std::recursive_timed_mutex`, and `std::shared_timed_mutex`. They shall
18
- meet the requirements set out in this section. In this description, `m`
19
- denotes 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
@@ -31,37 +31,39 @@ 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
- - `device_or_resource_busy` — if any native handle type manipulated is
37
- already locked.
38
  - `invalid_argument` — if any native handle type manipulated as part of
39
  mutex construction is incorrect.
40
 
41
  The implementation shall provide lock and unlock operations, as
42
  described below. For purposes of determining the existence of a data
43
  race, these behave as atomic operations ([[intro.multithread]]). The
44
  lock and unlock operations on a single mutex shall appear to occur in a
45
- single total order. this can be viewed as the modification order (
46
- [[intro.multithread]]) of the mutex. Construction and destruction of an
47
- object of a mutex type need not be thread-safe; other synchronization
48
- should be used to ensure that mutex objects are initialized and visible
49
- to other threads.
 
 
 
 
50
 
51
  The expression `m.lock()` shall be well-formed and have the following
52
  semantics:
53
 
54
- *Requires:* If `m` is of type `std::mutex`, `std::timed_mutex`, or
55
- `std::shared_timed_mutex`, the calling thread does not own the mutex.
56
 
57
  *Effects:* Blocks the calling thread until ownership of the mutex can be
58
  obtained for the calling thread.
59
 
60
- The calling thread owns the mutex.
61
 
62
- *Return type:* `void`
63
 
64
  *Synchronization:* Prior `unlock()` operations on the same object shall
65
  *synchronize with* ([[intro.multithread]]) this operation.
66
 
67
  *Throws:* `system_error` when an exception is
@@ -71,51 +73,53 @@ required ([[thread.req.exception]]).
71
 
72
  - `operation_not_permitted` — if the thread does not have the privilege
73
  to perform the operation.
74
  - `resource_deadlock_would_occur` — if the implementation detects that a
75
  deadlock would occur.
76
- - `device_or_resource_busy` — if the mutex is already locked and
77
- blocking is not possible.
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 `std::mutex`, `std::timed_mutex`, or
83
- `std::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. This
89
- spurious failure is normally uncommon, but allows interesting
90
- implementations based on a simple compare and exchange
91
- (Clause  [[atomics]]). An implementation should ensure that `try_lock()`
92
- does not consistently return `false` in the absence of contending mutex
93
- acquisitions.
94
 
95
- *Return type:* `bool`
 
 
 
 
 
 
 
96
 
97
  *Returns:* `true` if ownership of the mutex was obtained for the calling
98
  thread, otherwise `false`.
99
 
100
  *Synchronization:* If `try_lock()` returns `true`, prior `unlock()`
101
  operations on the same object *synchronize
102
- with* ([[intro.multithread]]) this operation. Since `lock()` does not
103
- synchronize with a failed subsequent `try_lock()`, the visibility rules
104
- are weak enough that little would be known about the state after a
105
- failure, even in the absence of spurious failures.
 
 
106
 
107
  *Throws:* Nothing.
108
 
109
  The expression `m.unlock()` shall be well-formed and have the following
110
  semantics:
111
 
112
- The calling thread shall own the mutex.
113
 
114
  *Effects:* Releases the calling thread’s ownership of the mutex.
115
 
116
- *Return type:* `void`
117
 
118
  *Synchronization:* This operation synchronizes
119
  with ([[intro.multithread]]) subsequent lock operations that obtain
120
  ownership on the same object.
121
 
@@ -135,11 +139,11 @@ namespace std {
135
 
136
  void lock();
137
  bool try_lock();
138
  void unlock();
139
 
140
- typedef implementation-defined native_handle_type; // See~[thread.req.native]
141
  native_handle_type native_handle(); // See~[thread.req.native]
142
  };
143
  }
144
  ```
145
 
@@ -147,26 +151,27 @@ The class `mutex` provides a non-recursive mutex with exclusive
147
  ownership semantics. If one thread owns a mutex object, attempts by
148
  another thread to acquire ownership of that object will fail (for
149
  `try_lock()`) or block (for `lock()`) until the owning thread has
150
  released ownership with a call to `unlock()`.
151
 
152
- After a thread `A` has called `unlock()`, releasing a mutex, it is
153
- possible for another thread `B` to lock the same mutex, observe that it
154
- is no longer in use, unlock it, and destroy it, before thread `A`
155
- appears to have returned from its unlock call. Implementations are
156
  required to handle such scenarios correctly, as long as thread `A`
157
  doesn’t access the mutex after the unlock call returns. These cases
158
  typically occur when a reference-counted object contains a mutex that is
159
- used to protect the reference count.
160
 
161
- The class `mutex` shall satisfy all the `Mutex` requirements (
162
  [[thread.mutex.requirements]]). It shall be a standard-layout class
163
  (Clause  [[class]]).
164
 
165
- A program may deadlock if the thread that owns a `mutex` object calls
166
- `lock()` on that object. If the implementation can detect the deadlock,
167
- a `resource_deadlock_would_occur` error condition may be observed.
 
168
 
169
  The behavior of a program is undefined if it destroys a `mutex` object
170
  owned by any thread or a thread terminates while owning a `mutex`
171
  object.
172
 
@@ -184,11 +189,11 @@ namespace std {
184
 
185
  void lock();
186
  bool try_lock() noexcept;
187
  void unlock();
188
 
189
- typedef implementation-defined native_handle_type; // See~[thread.req.native]
190
  native_handle_type native_handle(); // See~[thread.req.native]
191
  };
192
  }
193
  ```
194
 
@@ -196,13 +201,13 @@ The class `recursive_mutex` provides a recursive mutex with exclusive
196
  ownership semantics. If one thread owns a `recursive_mutex` object,
197
  attempts by another thread to acquire ownership of that object will fail
198
  (for `try_lock()`) or block (for `lock()`) until the first thread has
199
  completely released ownership.
200
 
201
- The class `recursive_mutex` shall satisfy all the Mutex requirements (
202
- [[thread.mutex.requirements]]). It shall be a standard-layout class
203
- (Clause  [[class]]).
204
 
205
  A thread that owns a `recursive_mutex` object may acquire additional
206
  levels of ownership by calling `lock()` or `try_lock()` on that object.
207
  It is unspecified how many levels of ownership may be acquired by a
208
  single thread. If a thread has already acquired the maximum level of
@@ -218,38 +223,39 @@ The behavior of a program is undefined if:
218
  - it destroys a `recursive_mutex` object owned by any thread or
219
  - a thread terminates while owning a `recursive_mutex` object.
220
 
221
  #### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
222
 
223
- The *timed mutex types* are the standard library types
224
- `std::timed_mutex`, `std::recursive_timed_mutex`, and
225
- `std::shared_timed_mutex`. They shall meet the requirements set out
226
- below. In this description, `m` denotes an object of a mutex type,
227
- `rel_time` denotes an object of an instantiation of `duration` (
228
- [[time.duration]]), and `abs_time` denotes an object of an instantiation
229
- of `time_point` ([[time.point]]).
230
 
231
  The timed mutex types shall meet the `TimedLockable` requirements (
232
  [[thread.req.lockable.timed]]).
233
 
234
  The expression `m.try_lock_for(rel_time)` shall be well-formed and have
235
  the following semantics:
236
 
237
- If `m` is of type `std::timed_mutex` or `std::shared_timed_mutex`, the
238
  calling thread does not own the mutex.
239
 
240
  *Effects:* The function attempts to obtain ownership of the mutex within
241
  the relative timeout ([[thread.req.timing]]) specified by `rel_time`.
242
  If the time specified by `rel_time` is less than or equal to
243
  `rel_time.zero()`, the function attempts to obtain ownership without
244
  blocking (as if by calling `try_lock()`). The function shall return
245
  within the timeout specified by `rel_time` only if it has obtained
246
- ownership of the mutex object. As with `try_lock()`, there is no
247
- guarantee that ownership will be obtained if the lock is available, but
248
- implementations are expected to make a strong effort to do so.
249
 
250
- *Return type:* `bool`
 
 
 
 
251
 
252
  *Returns:* `true` if ownership was obtained, otherwise `false`.
253
 
254
  *Synchronization:* If `try_lock_for()` returns `true`, prior `unlock()`
255
  operations on the same object *synchronize
@@ -258,23 +264,24 @@ with* ([[intro.multithread]]) this operation.
258
  *Throws:* Timeout-related exceptions ([[thread.req.timing]]).
259
 
260
  The expression `m.try_lock_until(abs_time)` shall be well-formed and
261
  have the following semantics:
262
 
263
- *Requires:* If `m` is of type `std::timed_mutex` or
264
- `std::shared_timed_mutex`, the calling thread does not own the mutex.
265
 
266
  *Effects:* The function attempts to obtain ownership of the mutex. If
267
  `abs_time` has already passed, the function attempts to obtain ownership
268
  without blocking (as if by calling `try_lock()`). The function shall
269
  return before the absolute timeout ([[thread.req.timing]]) specified by
270
- `abs_time` only if it has obtained ownership of the mutex object. As
271
- with `try_lock()`, there is no guarantee that ownership will be obtained
272
- if the lock is available, but implementations are expected to make a
273
- strong effort to do so.
274
 
275
- *Return type:* `bool`
 
 
 
 
276
 
277
  *Returns:* `true` if ownership was obtained, otherwise `false`.
278
 
279
  *Synchronization:* If `try_lock_until()` returns `true`, prior
280
  `unlock()` operations on the same object *synchronize
@@ -300,11 +307,11 @@ namespace std {
300
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
301
  template <class Clock, class Duration>
302
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
303
  void unlock();
304
 
305
- typedef implementation-defined native_handle_type; // See~[thread.req.native]
306
  native_handle_type native_handle(); // See~[thread.req.native]
307
  };
308
  }
309
  ```
310
 
@@ -314,11 +321,11 @@ by another thread to acquire ownership of that object will fail (for
314
  `try_lock()`) or block (for `lock()`, `try_lock_for()`, and
315
  `try_lock_until()`) until the owning thread has released ownership with
316
  a call to `unlock()` or the call to `try_lock_for()` or
317
  `try_lock_until()` times out (having failed to obtain ownership).
318
 
319
- The class `timed_mutex` shall satisfy all of the `TimedMutex`
320
  requirements ([[thread.timedmutex.requirements]]). It shall be a
321
  standard-layout class (Clause  [[class]]).
322
 
323
  The behavior of a program is undefined if:
324
 
@@ -346,11 +353,11 @@ namespace std {
346
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
347
  template <class Clock, class Duration>
348
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
349
  void unlock();
350
 
351
- typedef implementation-defined native_handle_type; // See~[thread.req.native]
352
  native_handle_type native_handle(); // See~[thread.req.native]
353
  };
354
  }
355
  ```
356
 
@@ -360,11 +367,11 @@ exclusive ownership semantics. If one thread owns a
360
  ownership of that object will fail (for `try_lock()`) or block (for
361
  `lock()`, `try_lock_for()`, and `try_lock_until()`) until the owning
362
  thread has completely released ownership or the call to `try_lock_for()`
363
  or `try_lock_until()` times out (having failed to obtain ownership).
364
 
365
- The class `recursive_timed_mutex` shall satisfy all of the `TimedMutex`
366
  requirements ([[thread.timedmutex.requirements]]). It shall be a
367
  standard-layout class (Clause  [[class]]).
368
 
369
  A thread that owns a `recursive_timed_mutex` object may acquire
370
  additional levels of ownership by calling `lock()`, `try_lock()`,
@@ -382,20 +389,17 @@ the object be acquired by another thread.
382
  The behavior of a program is undefined if:
383
 
384
  - it destroys a `recursive_timed_mutex` object owned by any thread, or
385
  - a thread terminates while owning a `recursive_timed_mutex` object.
386
 
387
- #### Shared timed mutex types <a id="thread.sharedtimedmutex.requirements">[[thread.sharedtimedmutex.requirements]]</a>
388
 
389
- The standard library type `std::shared_timed_mutex` is a *shared timed
390
- mutex type*. Shared timed mutex types shall meet the requirements of
391
- timed mutex types ([[thread.timedmutex.requirements]]), and
392
- additionally shall meet the requirements set out below. In this
393
- description, `m` denotes an object of a mutex type, `rel_type` denotes
394
- an object of an instantiation of `duration` ([[time.duration]]), and
395
- `abs_time` denotes an object of an instantiation of `time_point` (
396
- [[time.point]]).
397
 
398
  In addition to the exclusive lock ownership mode specified in 
399
  [[thread.mutex.requirements.mutex]], shared mutex types provide a
400
  *shared lock* ownership mode. Multiple execution agents can
401
  simultaneously hold a shared lock ownership of a shared mutex type. But
@@ -415,28 +419,26 @@ following semantics:
415
 
416
  *Effects:* Blocks the calling thread until shared ownership of the mutex
417
  can be obtained for the calling thread. If an exception is thrown then a
418
  shared lock shall not have been acquired for the current thread.
419
 
420
- The calling thread has a shared lock on the mutex.
421
 
422
  *Return type:* `void`.
423
 
424
  *Synchronization:* Prior `unlock()` operations on the same object shall
425
  synchronize with ([[intro.multithread]]) this operation.
426
 
427
- *Throws:* `system_error` when an exception is required
428
-  ([[thread.req.exception]]).
429
 
430
  *Error conditions:*
431
 
432
  - `operation_not_permitted` — if the thread does not have the privilege
433
  to perform the operation.
434
  - `resource_deadlock_would_occur` — if the implementation detects that a
435
  deadlock would occur.
436
- - `device_or_resource_busy` — if the mutex is already locked and
437
- blocking is not possible.
438
 
439
  The expression `m.unlock_shared()` shall be well-formed and have the
440
  following semantics:
441
 
442
  *Requires:* The calling thread shall hold a shared lock on the mutex.
@@ -467,15 +469,71 @@ other thread.
467
 
468
  *Returns:* `true` if the shared ownership lock was acquired, `false`
469
  otherwise.
470
 
471
  *Synchronization:* If `try_lock_shared()` returns `true`, prior
472
- `unlock()` operations on the same object synchronize with
473
-  ([[intro.multithread]]) this operation.
474
 
475
  *Throws:* Nothing.
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  The expression `m.try_lock_shared_for(rel_time)` shall be well-formed
478
  and have the following semantics:
479
 
480
  *Requires:* The calling thread has no ownership of the mutex.
481
 
@@ -483,14 +541,17 @@ and have the following semantics:
483
  thread within the relative timeout ([[thread.req.timing]]) specified by
484
  `rel_time`. If the time specified by `rel_time` is less than or equal to
485
  `rel_time.zero()`, the function attempts to obtain ownership without
486
  blocking (as if by calling `try_lock_shared()`). The function shall
487
  return within the timeout specified by `rel_time` only if it has
488
- obtained shared ownership of the mutex object. As with `try_lock()`,
489
- there is no guarantee that ownership will be obtained if the lock is
490
- available, but implementations are expected to make a strong effort to
491
- do so. If an exception is thrown then a shared lock shall not have been
 
 
 
492
  acquired for the current thread.
493
 
494
  *Return type:* `bool`.
495
 
496
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
@@ -509,14 +570,17 @@ and have the following semantics:
509
  *Effects:* The function attempts to obtain shared ownership of the
510
  mutex. If `abs_time` has already passed, the function attempts to obtain
511
  shared ownership without blocking (as if by calling
512
  `try_lock_shared()`). The function shall return before the absolute
513
  timeout ([[thread.req.timing]]) specified by `abs_time` only if it has
514
- obtained shared ownership of the mutex object. As with `try_lock()`,
515
- there is no guarantee that ownership will be obtained if the lock is
516
- available, but implementations are expected to make a strong effort to
517
- do so. If an exception is thrown then a shared lock shall not have been
 
 
 
518
  acquired for the current thread.
519
 
520
  *Return type:* `bool`.
521
 
522
  *Returns:* `true` if the shared lock was acquired, `false` otherwise.
@@ -563,14 +627,13 @@ namespace std {
563
  ```
564
 
565
  The class `shared_timed_mutex` provides a non-recursive mutex with
566
  shared ownership semantics.
567
 
568
- The class `shared_timed_mutex` shall satisfy all of the
569
- `SharedTimedMutex` requirements (
570
- [[thread.sharedtimedmutex.requirements]]). It shall be a standard-layout
571
- class (Clause  [[class]]).
572
 
573
  The behavior of a program is undefined if:
574
 
575
  - it destroys a `shared_timed_mutex` object owned by any thread,
576
  - a thread attempts to recursively gain any ownership of a
 
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
 
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
 
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
 
 
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
 
 
151
  ownership semantics. If one thread owns a mutex object, attempts by
152
  another thread to acquire ownership of that object will fail (for
153
  `try_lock()`) or block (for `lock()`) until the owning thread has
154
  released ownership with a call to `unlock()`.
155
 
156
+ [*Note 3*: After a thread `A` has called `unlock()`, releasing a mutex,
157
+ it is possible for another thread `B` to lock the same mutex, observe
158
+ that it is no longer in use, unlock it, and destroy it, before thread
159
+ `A` appears to have returned from its unlock call. Implementations are
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.
177
 
 
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
 
 
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
 
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
 
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*]
281
+
282
+ *Return type:* `bool`.
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
 
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
 
 
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
 
 
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
 
 
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()`,
 
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
 
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.
 
469
 
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:
485
+ shared_mutex();
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
518
+ `shared_mutex`, or
519
+ - a thread terminates while possessing any ownership of a
520
+ `shared_mutex`.
521
+
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
 
 
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.
 
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.
 
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