From Jason Turner

[thread.lock]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpvfva0qxl/{from.md → to.md} +225 -134
tmp/tmpvfva0qxl/{from.md → to.md} RENAMED
@@ -4,13 +4,15 @@ A *lock* is an object that holds a reference to a lockable object and
4
  may unlock the lockable object during the lock’s destruction (such as
5
  when leaving block scope). An execution agent may use a lock to aid in
6
  managing ownership of a lockable object in an exception safe manner. A
7
  lock is said to *own* a lockable object if it is currently managing the
8
  ownership of that lockable object for an execution agent. A lock does
9
- not manage the lifetime of the lockable object it references. Locks are
10
- intended to ease the burden of unlocking the lockable object under both
11
- normal and exceptional circumstances.
 
 
12
 
13
  Some lock constructors take tag types which describe what should be done
14
  with the lockable object during the lock’s construction.
15
 
16
  ``` cpp
@@ -19,35 +21,37 @@ namespace std {
19
  struct try_to_lock_t { }; // try to acquire ownership of the mutex
20
  // without blocking
21
  struct adopt_lock_t { }; // assume the calling thread has already
22
  // obtained mutex ownership and manage it
23
 
24
- constexpr defer_lock_t defer_lock { };
25
- constexpr try_to_lock_t try_to_lock { };
26
- constexpr adopt_lock_t adopt_lock { };
27
  }
28
  ```
29
 
30
  #### Class template `lock_guard` <a id="thread.lock.guard">[[thread.lock.guard]]</a>
31
 
32
  ``` cpp
33
  namespace std {
34
  template <class Mutex>
35
  class lock_guard {
36
  public:
37
- typedef Mutex mutex_type;
38
 
39
  explicit lock_guard(mutex_type& m);
40
  lock_guard(mutex_type& m, adopt_lock_t);
41
  ~lock_guard();
42
 
43
- lock_guard(lock_guard const&) = delete;
44
- lock_guard& operator=(lock_guard const&) = delete;
45
 
46
  private:
47
  mutex_type& pm; // exposition only
48
  };
 
 
49
  }
50
  ```
51
 
52
  An object of type `lock_guard` controls the ownership of a lockable
53
  object within a scope. A `lock_guard` object maintains ownership of a
@@ -59,43 +63,107 @@ object referenced by `pm` does not exist for the entire lifetime of the
59
 
60
  ``` cpp
61
  explicit lock_guard(mutex_type& m);
62
  ```
63
 
64
- If `mutex_type` is not a recursive mutex, the calling thread does not
65
- own the mutex `m`.
66
 
67
- *Effects:* `m.lock()`
68
 
69
- `&pm == &m`
70
 
71
  ``` cpp
72
  lock_guard(mutex_type& m, adopt_lock_t);
73
  ```
74
 
75
- The calling thread owns the mutex `m`.
76
 
77
- `&pm == &m`
78
 
79
  *Throws:* Nothing.
80
 
81
  ``` cpp
82
  ~lock_guard();
83
  ```
84
 
85
- *Effects:* `pm.unlock()`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  #### Class template `unique_lock` <a id="thread.lock.unique">[[thread.lock.unique]]</a>
88
 
89
  ``` cpp
90
  namespace std {
91
  template <class Mutex>
92
  class unique_lock {
93
  public:
94
- typedef Mutex mutex_type;
95
 
96
- // [thread.lock.unique.cons], construct/copy/destroy:
97
  unique_lock() noexcept;
98
  explicit unique_lock(mutex_type& m);
99
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
100
  unique_lock(mutex_type& m, try_to_lock_t);
101
  unique_lock(mutex_type& m, adopt_lock_t);
@@ -103,41 +171,43 @@ namespace std {
103
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
104
  template <class Rep, class Period>
105
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
106
  ~unique_lock();
107
 
108
- unique_lock(unique_lock const&) = delete;
109
- unique_lock& operator=(unique_lock const&) = delete;
110
 
111
  unique_lock(unique_lock&& u) noexcept;
112
  unique_lock& operator=(unique_lock&& u);
113
 
114
- // [thread.lock.unique.locking], locking:
115
  void lock();
116
  bool try_lock();
117
 
118
  template <class Rep, class Period>
119
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
120
  template <class Clock, class Duration>
121
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
122
 
123
  void unlock();
124
 
125
- // [thread.lock.unique.mod], modifiers:
126
  void swap(unique_lock& u) noexcept;
127
  mutex_type* release() noexcept;
128
 
129
- // [thread.lock.unique.obs], observers:
130
  bool owns_lock() const noexcept;
131
  explicit operator bool () const noexcept;
132
  mutex_type* mutex() const noexcept;
133
 
134
  private:
135
  mutex_type* pm; // exposition only
136
  bool owns; // exposition only
137
  };
138
 
 
 
139
  template <class Mutex>
140
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
141
  }
142
  ```
143
 
@@ -150,15 +220,16 @@ program is undefined if the contained pointer `pm` is not null and the
150
  lockable object pointed to by `pm` does not exist for the entire
151
  remaining lifetime ([[basic.life]]) of the `unique_lock` object. The
152
  supplied `Mutex` type shall meet the `BasicLockable` requirements (
153
  [[thread.req.lockable.basic]]).
154
 
155
- `unique_lock<Mutex>` meets the `BasicLockable` requirements. If `Mutex`
156
- meets the `Lockable` requirements ([[thread.req.lockable.req]]),
157
- `unique_lock<Mutex>` also meets the `Lockable` requirements; if `Mutex`
158
- meets the `TimedLockable` requirements ([[thread.req.lockable.timed]]),
159
- `unique_lock<Mutex>` also meets the `TimedLockable` requirements.
 
160
 
161
  ##### `unique_lock` constructors, destructor, and assignment <a id="thread.lock.unique.cons">[[thread.lock.unique.cons]]</a>
162
 
163
  ``` cpp
164
  unique_lock() noexcept;
@@ -170,81 +241,81 @@ unique_lock() noexcept;
170
 
171
  ``` cpp
172
  explicit unique_lock(mutex_type& m);
173
  ```
174
 
175
- If `mutex_type` is not a recursive mutex the calling thread does not own
176
- the mutex.
177
 
178
  *Effects:* Constructs an object of type `unique_lock` and calls
179
  `m.lock()`.
180
 
181
- *Postconditions:* `pm == &m` and `owns == true`.
182
 
183
  ``` cpp
184
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
185
  ```
186
 
187
  *Effects:* Constructs an object of type `unique_lock`.
188
 
189
- *Postconditions:* `pm == &m` and `owns == false`.
190
 
191
  ``` cpp
192
  unique_lock(mutex_type& m, try_to_lock_t);
193
  ```
194
 
195
- The supplied `Mutex` type shall meet the `Lockable`
196
  requirements ([[thread.req.lockable.req]]). If `mutex_type` is not a
197
  recursive mutex the calling thread does not own the mutex.
198
 
199
  *Effects:* Constructs an object of type `unique_lock` and calls
200
  `m.try_lock()`.
201
 
202
- *Postconditions:* `pm == &m` and `owns == res`, where `res` is the value
203
- returned by the call to `m.try_lock()`.
204
 
205
  ``` cpp
206
  unique_lock(mutex_type& m, adopt_lock_t);
207
  ```
208
 
209
- The calling thread own the mutex.
210
 
211
  *Effects:* Constructs an object of type `unique_lock`.
212
 
213
- *Postconditions:* `pm == &m` and `owns == true`.
214
 
215
  *Throws:* Nothing.
216
 
217
  ``` cpp
218
  template <class Clock, class Duration>
219
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
220
  ```
221
 
222
- If `mutex_type` is not a recursive mutex the calling thread does not own
223
- the mutex. The supplied `Mutex` type shall meet the `TimedLockable`
224
- requirements ([[thread.req.lockable.timed]]).
225
 
226
  *Effects:* Constructs an object of type `unique_lock` and calls
227
  `m.try_lock_until(abs_time)`.
228
 
229
- *Postconditions:* `pm == &m` and `owns == res`, where `res` is the value
230
- returned by the call to `m.try_lock_until(abs_time)`.
231
 
232
  ``` cpp
233
  template <class Rep, class Period>
234
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
235
  ```
236
 
237
- If `mutex_type` is not a recursive mutex the calling thread does not own
238
- the mutex. The supplied `Mutex` type shall meet the `TimedLockable`
239
- requirements ([[thread.req.lockable.timed]]).
240
 
241
  *Effects:* Constructs an object of type `unique_lock` and calls
242
  `m.try_lock_for(rel_time)`.
243
 
244
- *Postconditions:* `pm == &m` and `owns == res`, where `res` is the value
245
- returned by the call to `m.try_lock_for(rel_time)`.
246
 
247
  ``` cpp
248
  unique_lock(unique_lock&& u) noexcept;
249
  ```
250
 
@@ -260,13 +331,13 @@ unique_lock& operator=(unique_lock&& u);
260
 
261
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
262
  the state of `u` just prior to this construction), `u.pm == 0` and
263
  `u.owns == false`.
264
 
265
- With a recursive mutex it is possible for both `*this` and `u` to own
266
- the same mutex before the assignment. In this case, `*this` will own the
267
- mutex after the assignment and `u` will not.
268
 
269
  *Throws:* Nothing.
270
 
271
  ``` cpp
272
  ~unique_lock();
@@ -278,96 +349,104 @@ mutex after the assignment and `u` will not.
278
 
279
  ``` cpp
280
  void lock();
281
  ```
282
 
283
- *Effects:* `pm->lock()`
284
 
285
- `owns == true`
286
 
287
- *Throws:* Any exception thrown by `pm->lock()`. `system_error` if an
288
- exception is required ([[thread.req.exception]]). `system_error` with
289
- an error condition of `operation_not_permitted` if `pm` is 0.
290
- `system_error` with an error condition of
291
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
292
 
293
  ``` cpp
294
  bool try_lock();
295
  ```
296
 
297
- The supplied `Mutex` shall meet the `Lockable`
298
  requirements ([[thread.req.lockable.req]]).
299
 
300
- *Effects:* `pm->try_lock()`
301
 
302
  *Returns:* The value returned by the call to `try_lock()`.
303
 
304
- `owns == res`, where `res` is the value returned by the call to
305
- `try_lock()`.
306
 
307
- *Throws:* Any exception thrown by `pm->try_lock()`. `system_error` if an
308
- exception is required ([[thread.req.exception]]). `system_error` with
309
- an error condition of `operation_not_permitted` if `pm` is 0.
310
- `system_error` with an error condition of
311
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
312
 
313
  ``` cpp
314
  template <class Clock, class Duration>
315
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
316
  ```
317
 
318
  *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
319
  requirements ([[thread.req.lockable.timed]]).
320
 
321
- *Effects:* `pm->try_lock_until(abs_time)`
322
 
323
  *Returns:* The value returned by the call to `try_lock_until(abs_time)`.
324
 
325
- `owns == res`, where `res` is the value returned by the call to
326
- `try_lock_until(abs_time)`.
327
 
328
  *Throws:* Any exception thrown by `pm->try_lock_until()`. `system_error`
329
- if an exception is required ([[thread.req.exception]]). `system_error`
330
- with an error condition of `operation_not_permitted` if `pm` is 0.
331
- `system_error` with an error condition of
332
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
333
 
334
  ``` cpp
335
  template <class Rep, class Period>
336
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
337
  ```
338
 
339
  *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
340
  requirements ([[thread.req.lockable.timed]]).
341
 
342
- *Effects:* `pm->try_lock_for(rel_time)`.
343
 
344
  *Returns:* The value returned by the call to `try_lock_until(rel_time)`.
345
 
346
- `owns == res`, where `res` is the value returned by the call to
347
- `try_lock_for(rel_time)`.
348
 
349
  *Throws:* Any exception thrown by `pm->try_lock_for()`. `system_error`
350
- if an exception is required ([[thread.req.exception]]). `system_error`
351
- with an error condition of `operation_not_permitted` if `pm` is 0.
352
- `system_error` with an error condition of
353
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
354
 
355
  ``` cpp
356
  void unlock();
357
  ```
358
 
359
- *Effects:* `pm->unlock()`
360
 
361
- `owns == false`
362
 
363
  *Throws:* `system_error` when an exception is
364
  required ([[thread.req.exception]]).
365
 
366
  *Error conditions:*
367
 
368
- - `operation_not_permitted` — if on entry `owns` is false.
369
 
370
  ##### `unique_lock` modifiers <a id="thread.lock.unique.mod">[[thread.lock.unique.mod]]</a>
371
 
372
  ``` cpp
373
  void swap(unique_lock& u) noexcept;
@@ -386,43 +465,42 @@ mutex_type* release() noexcept;
386
  ``` cpp
387
  template <class Mutex>
388
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
389
  ```
390
 
391
- *Effects:* `x.swap(y)`
392
 
393
  ##### `unique_lock` observers <a id="thread.lock.unique.obs">[[thread.lock.unique.obs]]</a>
394
 
395
  ``` cpp
396
  bool owns_lock() const noexcept;
397
  ```
398
 
399
- *Returns:* `owns`
400
 
401
  ``` cpp
402
  explicit operator bool() const noexcept;
403
  ```
404
 
405
- *Returns:* `owns`
406
 
407
  ``` cpp
408
  mutex_type *mutex() const noexcept;
409
  ```
410
 
411
- *Returns:* `pm`
412
 
413
  #### Class template `shared_lock` <a id="thread.lock.shared">[[thread.lock.shared]]</a>
414
 
415
  ``` cpp
416
  namespace std {
417
-
418
  template <class Mutex>
419
  class shared_lock {
420
  public:
421
- typedef Mutex mutex_type;
422
 
423
- // Shared locking
424
  shared_lock() noexcept;
425
  explicit shared_lock(mutex_type& m); // blocking
426
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
427
  shared_lock(mutex_type& m, try_to_lock_t);
428
  shared_lock(mutex_type& m, adopt_lock_t);
@@ -432,42 +510,44 @@ public:
432
  template <class Rep, class Period>
433
  shared_lock(mutex_type& m,
434
  const chrono::duration<Rep, Period>& rel_time);
435
  ~shared_lock();
436
 
437
- shared_lock(shared_lock const&) = delete;
438
- shared_lock& operator=(shared_lock const&) = delete;
439
 
440
  shared_lock(shared_lock&& u) noexcept;
441
  shared_lock& operator=(shared_lock&& u) noexcept;
442
 
 
443
  void lock(); // blocking
444
  bool try_lock();
445
  template <class Rep, class Period>
446
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
447
  template <class Clock, class Duration>
448
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
449
  void unlock();
450
 
451
- // Setters
452
  void swap(shared_lock& u) noexcept;
453
  mutex_type* release() noexcept;
454
 
455
- // Getters
456
  bool owns_lock() const noexcept;
457
  explicit operator bool () const noexcept;
458
  mutex_type* mutex() const noexcept;
459
 
460
  private:
461
  mutex_type* pm; // exposition only
462
  bool owns; // exposition only
463
  };
464
 
 
 
465
  template <class Mutex>
466
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
467
-
468
- } // std
469
  ```
470
 
471
  An object of type `shared_lock` controls the shared ownership of a
472
  lockable object within a scope. Shared ownership of the lockable object
473
  may be acquired at construction or after construction, and may be
@@ -477,12 +557,12 @@ a program is undefined if the contained pointer `pm` is not null and the
477
  lockable object pointed to by `pm` does not exist for the entire
478
  remaining lifetime ([[basic.life]]) of the `shared_lock` object. The
479
  supplied `Mutex` type shall meet the shared mutex requirements (
480
  [[thread.sharedtimedmutex.requirements]]).
481
 
482
- `shared_lock<Mutex>` meets the `TimedLockable` requirements (
483
- [[thread.req.lockable.timed]]).
484
 
485
  ##### `shared_lock` constructors, destructor, and assignment <a id="thread.lock.shared.cons">[[thread.lock.shared.cons]]</a>
486
 
487
  ``` cpp
488
  shared_lock() noexcept;
@@ -500,19 +580,19 @@ explicit shared_lock(mutex_type& m);
500
  mode.
501
 
502
  *Effects:* Constructs an object of type `shared_lock` and calls
503
  `m.lock_shared()`.
504
 
505
- *Postconditions:* `pm == &m` and `owns == true`.
506
 
507
  ``` cpp
508
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
509
  ```
510
 
511
  *Effects:* Constructs an object of type `shared_lock`.
512
 
513
- *Postconditions:* `pm == &m` and `owns == false`.
514
 
515
  ``` cpp
516
  shared_lock(mutex_type& m, try_to_lock_t);
517
  ```
518
 
@@ -520,22 +600,22 @@ shared_lock(mutex_type& m, try_to_lock_t);
520
  mode.
521
 
522
  *Effects:* Constructs an object of type `shared_lock` and calls
523
  `m.try_lock_shared()`.
524
 
525
- *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
526
- returned by the call to `m.try_lock_shared()`.
527
 
528
  ``` cpp
529
  shared_lock(mutex_type& m, adopt_lock_t);
530
  ```
531
 
532
  *Requires:* The calling thread has shared ownership of the mutex.
533
 
534
  *Effects:* Constructs an object of type `shared_lock`.
535
 
536
- *Postconditions:* `pm == &m` and `owns == true`.
537
 
538
  ``` cpp
539
  template <class Clock, class Duration>
540
  shared_lock(mutex_type& m,
541
  const chrono::time_point<Clock, Duration>& abs_time);
@@ -545,12 +625,12 @@ template <class Clock, class Duration>
545
  mode.
546
 
547
  *Effects:* Constructs an object of type `shared_lock` and calls
548
  `m.try_lock_shared_until(abs_time)`.
549
 
550
- *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
551
- returned by the call to `m.try_lock_shared_until(abs_time)`.
552
 
553
  ``` cpp
554
  template <class Rep, class Period>
555
  shared_lock(mutex_type& m,
556
  const chrono::duration<Rep, Period>& rel_time);
@@ -560,12 +640,12 @@ template <class Rep, class Period>
560
  mode.
561
 
562
  *Effects:* Constructs an object of type `shared_lock` and calls
563
  `m.try_lock_shared_for(rel_time)`.
564
 
565
- *Postconditions:* `pm == &m` and `owns == res` where `res` is the value
566
- returned by the call to `m.try_lock_shared_for(rel_time)`.
567
 
568
  ``` cpp
569
  ~shared_lock();
570
  ```
571
 
@@ -573,106 +653,117 @@ returned by the call to `m.try_lock_shared_for(rel_time)`.
573
 
574
  ``` cpp
575
  shared_lock(shared_lock&& sl) noexcept;
576
  ```
577
 
578
- *Postconditions:* `pm == &sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
579
  is the state of `sl` just prior to this construction),
580
  `sl.pm == nullptr` and `sl.owns == false`.
581
 
582
  ``` cpp
583
  shared_lock& operator=(shared_lock&& sl) noexcept;
584
  ```
585
 
586
  *Effects:* If `owns` calls `pm->unlock_shared()`.
587
 
588
- *Postconditions:* `pm == &sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
589
  is the state of `sl` just prior to this assignment), `sl.pm == nullptr`
590
  and `sl.owns == false`.
591
 
592
  ##### `shared_lock` locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
593
 
594
  ``` cpp
595
  void lock();
596
  ```
597
 
598
- *Effects:* `pm->lock_shared()`.
599
 
600
  *Postconditions:* `owns == true`.
601
 
602
- *Throws:* Any exception thrown by `pm->lock_shared()`. `system_error` if
603
- an exception is required ([[thread.req.exception]]). `system_error`
604
- with an error condition of `operation_not_permitted` if `pm` is
605
- `nullptr`. `system_error` with an error condition of
606
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
607
 
608
  ``` cpp
609
  bool try_lock();
610
  ```
611
 
612
- *Effects:* `pm->try_lock_shared()`.
613
 
614
  *Returns:* The value returned by the call to `pm->try_lock_shared()`.
615
 
616
  *Postconditions:* `owns == res`, where `res` is the value returned by
617
  the call to `pm->try_lock_shared()`.
618
 
619
  *Throws:* Any exception thrown by `pm->try_lock_shared()`.
620
- `system_error` if an exception is required ([[thread.req.exception]]).
621
- `system_error` with an error condition of `operation_not_permitted` if
622
- `pm` is `nullptr`. `system_error` with an error condition of
623
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
 
624
 
625
  ``` cpp
626
  template <class Clock, class Duration>
627
  bool
628
  try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
629
  ```
630
 
631
- *Effects:* `pm->try_lock_shared_until(abs_time)`.
632
 
633
  *Returns:* The value returned by the call to
634
  `pm->try_lock_shared_until(abs_time)`.
635
 
636
  *Postconditions:* `owns == res`, where `res` is the value returned by
637
  the call to `pm->try_lock_shared_until(abs_time)`.
638
 
639
  *Throws:* Any exception thrown by `pm->try_lock_shared_until(abs_time)`.
640
- `system_error` if an exception is required ([[thread.req.exception]]).
641
- `system_error` with an error condition of `operation_not_permitted` if
642
- `pm` is `nullptr`. `system_error` with an error condition of
643
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
 
644
 
645
  ``` cpp
646
  template <class Rep, class Period>
647
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
648
  ```
649
 
650
- *Effects:* `pm->try_lock_shared_for(rel_time)`.
651
 
652
  *Returns:* The value returned by the call to
653
  `pm->try_lock_shared_for(rel_time)`.
654
 
655
  *Postconditions:* `owns == res`, where `res` is the value returned by
656
  the call to `pm->try_lock_shared_for(rel_time)`.
657
 
658
  *Throws:* Any exception thrown by `pm->try_lock_shared_for(rel_time)`.
659
- `system_error` if an exception is required  ([[thread.req.exception]]).
660
- `system_error` with an error condition of `operation_not_permitted` if
661
- `pm` is `nullptr`. `system_error` with an error condition of
662
- `resource_deadlock_would_occur` if on entry `owns` is `true`.
 
 
 
663
 
664
  ``` cpp
665
  void unlock();
666
  ```
667
 
668
- *Effects:* `pm->unlock_shared()`.
669
 
670
  *Postconditions:* `owns == false`.
671
 
672
- *Throws:* `system_error` when an exception is required
673
-  ([[thread.req.exception]]).
674
 
675
  *Error conditions:*
676
 
677
  - `operation_not_permitted` — if on entry `owns` is `false`.
678
 
@@ -695,11 +786,11 @@ mutex_type* release() noexcept;
695
  ``` cpp
696
  template <class Mutex>
697
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
698
  ```
699
 
700
- *Effects:* `x.swap(y)`.
701
 
702
  ##### `shared_lock` observers <a id="thread.lock.shared.obs">[[thread.lock.shared.obs]]</a>
703
 
704
  ``` cpp
705
  bool owns_lock() const noexcept;
 
4
  may unlock the lockable object during the lock’s destruction (such as
5
  when leaving block scope). An execution agent may use a lock to aid in
6
  managing ownership of a lockable object in an exception safe manner. A
7
  lock is said to *own* a lockable object if it is currently managing the
8
  ownership of that lockable object for an execution agent. A lock does
9
+ not manage the lifetime of the lockable object it references.
10
+
11
+ [*Note 1*: Locks are intended to ease the burden of unlocking the
12
+ lockable object under both normal and exceptional
13
+ circumstances. — *end note*]
14
 
15
  Some lock constructors take tag types which describe what should be done
16
  with the lockable object during the lock’s construction.
17
 
18
  ``` cpp
 
21
  struct try_to_lock_t { }; // try to acquire ownership of the mutex
22
  // without blocking
23
  struct adopt_lock_t { }; // assume the calling thread has already
24
  // obtained mutex ownership and manage it
25
 
26
+ inline constexpr defer_lock_t defer_lock { };
27
+ inline constexpr try_to_lock_t try_to_lock { };
28
+ inline constexpr adopt_lock_t adopt_lock { };
29
  }
30
  ```
31
 
32
  #### Class template `lock_guard` <a id="thread.lock.guard">[[thread.lock.guard]]</a>
33
 
34
  ``` cpp
35
  namespace std {
36
  template <class Mutex>
37
  class lock_guard {
38
  public:
39
+ using mutex_type = Mutex;
40
 
41
  explicit lock_guard(mutex_type& m);
42
  lock_guard(mutex_type& m, adopt_lock_t);
43
  ~lock_guard();
44
 
45
+ lock_guard(const lock_guard&) = delete;
46
+ lock_guard& operator=(const lock_guard&) = delete;
47
 
48
  private:
49
  mutex_type& pm; // exposition only
50
  };
51
+
52
+ template<class Mutex> lock_guard(lock_guard<Mutex>) -> lock_guard<Mutex>;
53
  }
54
  ```
55
 
56
  An object of type `lock_guard` controls the ownership of a lockable
57
  object within a scope. A `lock_guard` object maintains ownership of a
 
63
 
64
  ``` cpp
65
  explicit lock_guard(mutex_type& m);
66
  ```
67
 
68
+ *Requires:* If `mutex_type` is not a recursive mutex, the calling thread
69
+ does not own the mutex `m`.
70
 
71
+ *Effects:* As if by `m.lock()`.
72
 
73
+ *Postconditions:* `&pm == &m`
74
 
75
  ``` cpp
76
  lock_guard(mutex_type& m, adopt_lock_t);
77
  ```
78
 
79
+ *Requires:* The calling thread owns the mutex `m`.
80
 
81
+ *Postconditions:* `&pm == &m`
82
 
83
  *Throws:* Nothing.
84
 
85
  ``` cpp
86
  ~lock_guard();
87
  ```
88
 
89
+ *Effects:* As if by `pm.unlock()`.
90
+
91
+ #### Class template `scoped_lock` <a id="thread.lock.scoped">[[thread.lock.scoped]]</a>
92
+
93
+ ``` cpp
94
+ namespace std {
95
+ template <class... MutexTypes>
96
+ class scoped_lock {
97
+ public:
98
+ using mutex_type = Mutex; // If MutexTypes... consists of the single type Mutex
99
+
100
+ explicit scoped_lock(MutexTypes&... m);
101
+ explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
102
+ ~scoped_lock();
103
+
104
+ scoped_lock(const scoped_lock&) = delete;
105
+ scoped_lock& operator=(const scoped_lock&) = delete;
106
+
107
+ private:
108
+ tuple<MutexTypes&...> pm; // exposition only
109
+ };
110
+
111
+ template<class... MutexTypes>
112
+ scoped_lock(scoped_lock<MutexTypes...>) -> scoped_lock<MutexTypes...>;
113
+ }
114
+ ```
115
+
116
+ An object of type `scoped_lock` controls the ownership of lockable
117
+ objects within a scope. A `scoped_lock` object maintains ownership of
118
+ lockable objects throughout the `scoped_lock` object’s lifetime (
119
+ [[basic.life]]). The behavior of a program is undefined if the lockable
120
+ objects referenced by `pm` do not exist for the entire lifetime of the
121
+ `scoped_lock` object. When `sizeof...(MutexTypes)` is `1`, the supplied
122
+ `Mutex` type shall meet the `BasicLockable` requirements (
123
+ [[thread.req.lockable.basic]]). Otherwise, each of the mutex types shall
124
+ meet the `Lockable` requirements ([[thread.req.lockable.req]]).
125
+
126
+ ``` cpp
127
+ explicit scoped_lock(MutexTypes&... m);
128
+ ```
129
+
130
+ *Requires:* If a `MutexTypes` type is not a recursive mutex, the calling
131
+ thread does not own the corresponding mutex element of `m`.
132
+
133
+ *Effects:* Initializes `pm` with `tie(m...)`. Then if
134
+ `sizeof...(MutexTypes)` is `0`, no effects. Otherwise if
135
+ `sizeof...(MutexTypes)` is `1`, then `m.lock()`. Otherwise,
136
+ `lock(m...)`.
137
+
138
+ ``` cpp
139
+ explicit scoped_lock(MutexTypes&... m, adopt_lock_t);
140
+ ```
141
+
142
+ *Requires:* The calling thread owns all the mutexes in `m`.
143
+
144
+ *Effects:* Initializes `pm` with `tie(m...)`.
145
+
146
+ *Throws:* Nothing.
147
+
148
+ ``` cpp
149
+ ~scoped_lock();
150
+ ```
151
+
152
+ *Effects:* For all `i` in \[`0`, `sizeof...(MutexTypes)`),
153
+ `get<i>(pm).unlock()`.
154
 
155
  #### Class template `unique_lock` <a id="thread.lock.unique">[[thread.lock.unique]]</a>
156
 
157
  ``` cpp
158
  namespace std {
159
  template <class Mutex>
160
  class unique_lock {
161
  public:
162
+ using mutex_type = Mutex;
163
 
164
+ // [thread.lock.unique.cons], construct/copy/destroy
165
  unique_lock() noexcept;
166
  explicit unique_lock(mutex_type& m);
167
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
168
  unique_lock(mutex_type& m, try_to_lock_t);
169
  unique_lock(mutex_type& m, adopt_lock_t);
 
171
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
172
  template <class Rep, class Period>
173
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
174
  ~unique_lock();
175
 
176
+ unique_lock(const unique_lock&) = delete;
177
+ unique_lock& operator=(const unique_lock&) = delete;
178
 
179
  unique_lock(unique_lock&& u) noexcept;
180
  unique_lock& operator=(unique_lock&& u);
181
 
182
+ // [thread.lock.unique.locking], locking
183
  void lock();
184
  bool try_lock();
185
 
186
  template <class Rep, class Period>
187
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
188
  template <class Clock, class Duration>
189
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
190
 
191
  void unlock();
192
 
193
+ // [thread.lock.unique.mod], modifiers
194
  void swap(unique_lock& u) noexcept;
195
  mutex_type* release() noexcept;
196
 
197
+ // [thread.lock.unique.obs], observers
198
  bool owns_lock() const noexcept;
199
  explicit operator bool () const noexcept;
200
  mutex_type* mutex() const noexcept;
201
 
202
  private:
203
  mutex_type* pm; // exposition only
204
  bool owns; // exposition only
205
  };
206
 
207
+ template<class Mutex> unique_lock(unique_lock<Mutex>) -> unique_lock<Mutex>;
208
+
209
  template <class Mutex>
210
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
211
  }
212
  ```
213
 
 
220
  lockable object pointed to by `pm` does not exist for the entire
221
  remaining lifetime ([[basic.life]]) of the `unique_lock` object. The
222
  supplied `Mutex` type shall meet the `BasicLockable` requirements (
223
  [[thread.req.lockable.basic]]).
224
 
225
+ [*Note 1*: `unique_lock<Mutex>` meets the `BasicLockable` requirements.
226
+ If `Mutex` meets the `Lockable` requirements (
227
+ [[thread.req.lockable.req]]), `unique_lock<Mutex>` also meets the
228
+ `Lockable` requirements; if `Mutex` meets the `TimedLockable`
229
+ requirements ([[thread.req.lockable.timed]]), `unique_lock<Mutex>` also
230
+ meets the `TimedLockable` requirements. — *end note*]
231
 
232
  ##### `unique_lock` constructors, destructor, and assignment <a id="thread.lock.unique.cons">[[thread.lock.unique.cons]]</a>
233
 
234
  ``` cpp
235
  unique_lock() noexcept;
 
241
 
242
  ``` cpp
243
  explicit unique_lock(mutex_type& m);
244
  ```
245
 
246
+ *Requires:* If `mutex_type` is not a recursive mutex the calling thread
247
+ does not own the mutex.
248
 
249
  *Effects:* Constructs an object of type `unique_lock` and calls
250
  `m.lock()`.
251
 
252
+ *Postconditions:* `pm == addressof(m)` and `owns == true`.
253
 
254
  ``` cpp
255
  unique_lock(mutex_type& m, defer_lock_t) noexcept;
256
  ```
257
 
258
  *Effects:* Constructs an object of type `unique_lock`.
259
 
260
+ *Postconditions:* `pm == addressof(m)` and `owns == false`.
261
 
262
  ``` cpp
263
  unique_lock(mutex_type& m, try_to_lock_t);
264
  ```
265
 
266
+ *Requires:* The supplied `Mutex` type shall meet the `Lockable`
267
  requirements ([[thread.req.lockable.req]]). If `mutex_type` is not a
268
  recursive mutex the calling thread does not own the mutex.
269
 
270
  *Effects:* Constructs an object of type `unique_lock` and calls
271
  `m.try_lock()`.
272
 
273
+ *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
274
+ the value returned by the call to `m.try_lock()`.
275
 
276
  ``` cpp
277
  unique_lock(mutex_type& m, adopt_lock_t);
278
  ```
279
 
280
+ *Requires:* The calling thread owns the mutex.
281
 
282
  *Effects:* Constructs an object of type `unique_lock`.
283
 
284
+ *Postconditions:* `pm == addressof(m)` and `owns == true`.
285
 
286
  *Throws:* Nothing.
287
 
288
  ``` cpp
289
  template <class Clock, class Duration>
290
  unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
291
  ```
292
 
293
+ *Requires:* If `mutex_type` is not a recursive mutex the calling thread
294
+ does not own the mutex. The supplied `Mutex` type shall meet the
295
+ `TimedLockable` requirements ([[thread.req.lockable.timed]]).
296
 
297
  *Effects:* Constructs an object of type `unique_lock` and calls
298
  `m.try_lock_until(abs_time)`.
299
 
300
+ *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
301
+ the value returned by the call to `m.try_lock_until(abs_time)`.
302
 
303
  ``` cpp
304
  template <class Rep, class Period>
305
  unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
306
  ```
307
 
308
+ *Requires:* If `mutex_type` is not a recursive mutex the calling thread
309
+ does not own the mutex. The supplied `Mutex` type shall meet the
310
+ `TimedLockable` requirements ([[thread.req.lockable.timed]]).
311
 
312
  *Effects:* Constructs an object of type `unique_lock` and calls
313
  `m.try_lock_for(rel_time)`.
314
 
315
+ *Postconditions:* `pm == addressof(m)` and `owns == res`, where `res` is
316
+ the value returned by the call to `m.try_lock_for(rel_time)`.
317
 
318
  ``` cpp
319
  unique_lock(unique_lock&& u) noexcept;
320
  ```
321
 
 
331
 
332
  *Postconditions:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is
333
  the state of `u` just prior to this construction), `u.pm == 0` and
334
  `u.owns == false`.
335
 
336
+ [*Note 1*: With a recursive mutex it is possible for both `*this` and
337
+ `u` to own the same mutex before the assignment. In this case, `*this`
338
+ will own the mutex after the assignment and `u` will not. — *end note*]
339
 
340
  *Throws:* Nothing.
341
 
342
  ``` cpp
343
  ~unique_lock();
 
349
 
350
  ``` cpp
351
  void lock();
352
  ```
353
 
354
+ *Effects:* As if by `pm->lock()`.
355
 
356
+ *Postconditions:* `owns == true`.
357
 
358
+ *Throws:* Any exception thrown by `pm->lock()`. `system_error` when an
359
+ exception is required ([[thread.req.exception]]).
360
+
361
+ *Error conditions:*
362
+
363
+ - `operation_not_permitted` — if `pm` is `nullptr`.
364
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
365
 
366
  ``` cpp
367
  bool try_lock();
368
  ```
369
 
370
+ *Requires:* The supplied `Mutex` shall meet the `Lockable`
371
  requirements ([[thread.req.lockable.req]]).
372
 
373
+ *Effects:* As if by `pm->try_lock()`.
374
 
375
  *Returns:* The value returned by the call to `try_lock()`.
376
 
377
+ *Postconditions:* `owns == res`, where `res` is the value returned by
378
+ the call to `try_lock()`.
379
 
380
+ *Throws:* Any exception thrown by `pm->try_lock()`. `system_error` when
381
+ an exception is required ([[thread.req.exception]]).
382
+
383
+ *Error conditions:*
384
+
385
+ - `operation_not_permitted` — if `pm` is `nullptr`.
386
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
387
 
388
  ``` cpp
389
  template <class Clock, class Duration>
390
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
391
  ```
392
 
393
  *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
394
  requirements ([[thread.req.lockable.timed]]).
395
 
396
+ *Effects:* As if by `pm->try_lock_until(abs_time)`.
397
 
398
  *Returns:* The value returned by the call to `try_lock_until(abs_time)`.
399
 
400
+ *Postconditions:* `owns == res`, where `res` is the value returned by
401
+ the call to `try_lock_until(abs_time)`.
402
 
403
  *Throws:* Any exception thrown by `pm->try_lock_until()`. `system_error`
404
+ when an exception is required ([[thread.req.exception]]).
405
+
406
+ *Error conditions:*
407
+
408
+ - `operation_not_permitted` — if `pm` is `nullptr`.
409
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
410
 
411
  ``` cpp
412
  template <class Rep, class Period>
413
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
414
  ```
415
 
416
  *Requires:* The supplied `Mutex` type shall meet the `TimedLockable`
417
  requirements ([[thread.req.lockable.timed]]).
418
 
419
+ *Effects:* As if by `pm->try_lock_for(rel_time)`.
420
 
421
  *Returns:* The value returned by the call to `try_lock_until(rel_time)`.
422
 
423
+ *Postconditions:* `owns == res`, where `res` is the value returned by
424
+ the call to `try_lock_for(rel_time)`.
425
 
426
  *Throws:* Any exception thrown by `pm->try_lock_for()`. `system_error`
427
+ when an exception is required ([[thread.req.exception]]).
428
+
429
+ *Error conditions:*
430
+
431
+ - `operation_not_permitted` — if `pm` is `nullptr`.
432
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
433
 
434
  ``` cpp
435
  void unlock();
436
  ```
437
 
438
+ *Effects:* As if by `pm->unlock()`.
439
 
440
+ *Postconditions:* `owns == false`.
441
 
442
  *Throws:* `system_error` when an exception is
443
  required ([[thread.req.exception]]).
444
 
445
  *Error conditions:*
446
 
447
+ - `operation_not_permitted` — if on entry `owns` is `false`.
448
 
449
  ##### `unique_lock` modifiers <a id="thread.lock.unique.mod">[[thread.lock.unique.mod]]</a>
450
 
451
  ``` cpp
452
  void swap(unique_lock& u) noexcept;
 
465
  ``` cpp
466
  template <class Mutex>
467
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
468
  ```
469
 
470
+ *Effects:* As if by `x.swap(y)`.
471
 
472
  ##### `unique_lock` observers <a id="thread.lock.unique.obs">[[thread.lock.unique.obs]]</a>
473
 
474
  ``` cpp
475
  bool owns_lock() const noexcept;
476
  ```
477
 
478
+ *Returns:* `owns`.
479
 
480
  ``` cpp
481
  explicit operator bool() const noexcept;
482
  ```
483
 
484
+ *Returns:* `owns`.
485
 
486
  ``` cpp
487
  mutex_type *mutex() const noexcept;
488
  ```
489
 
490
+ *Returns:* `pm`.
491
 
492
  #### Class template `shared_lock` <a id="thread.lock.shared">[[thread.lock.shared]]</a>
493
 
494
  ``` cpp
495
  namespace std {
 
496
  template <class Mutex>
497
  class shared_lock {
498
  public:
499
+ using mutex_type = Mutex;
500
 
501
+ // [thread.lock.shared.cons], construct/copy/destroy
502
  shared_lock() noexcept;
503
  explicit shared_lock(mutex_type& m); // blocking
504
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
505
  shared_lock(mutex_type& m, try_to_lock_t);
506
  shared_lock(mutex_type& m, adopt_lock_t);
 
510
  template <class Rep, class Period>
511
  shared_lock(mutex_type& m,
512
  const chrono::duration<Rep, Period>& rel_time);
513
  ~shared_lock();
514
 
515
+ shared_lock(const shared_lock&) = delete;
516
+ shared_lock& operator=(const shared_lock&) = delete;
517
 
518
  shared_lock(shared_lock&& u) noexcept;
519
  shared_lock& operator=(shared_lock&& u) noexcept;
520
 
521
+ // [thread.lock.shared.locking], locking
522
  void lock(); // blocking
523
  bool try_lock();
524
  template <class Rep, class Period>
525
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
526
  template <class Clock, class Duration>
527
  bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
528
  void unlock();
529
 
530
+ // [thread.lock.shared.mod], modifiers
531
  void swap(shared_lock& u) noexcept;
532
  mutex_type* release() noexcept;
533
 
534
+ // [thread.lock.shared.obs], observers
535
  bool owns_lock() const noexcept;
536
  explicit operator bool () const noexcept;
537
  mutex_type* mutex() const noexcept;
538
 
539
  private:
540
  mutex_type* pm; // exposition only
541
  bool owns; // exposition only
542
  };
543
 
544
+ template<class Mutex> shared_lock(shared_lock<Mutex>) -> shared_lock<Mutex>;
545
+
546
  template <class Mutex>
547
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
548
+ }
 
549
  ```
550
 
551
  An object of type `shared_lock` controls the shared ownership of a
552
  lockable object within a scope. Shared ownership of the lockable object
553
  may be acquired at construction or after construction, and may be
 
557
  lockable object pointed to by `pm` does not exist for the entire
558
  remaining lifetime ([[basic.life]]) of the `shared_lock` object. The
559
  supplied `Mutex` type shall meet the shared mutex requirements (
560
  [[thread.sharedtimedmutex.requirements]]).
561
 
562
+ [*Note 1*: `shared_lock<Mutex>` meets the `TimedLockable`
563
+ requirements ([[thread.req.lockable.timed]]). — *end note*]
564
 
565
  ##### `shared_lock` constructors, destructor, and assignment <a id="thread.lock.shared.cons">[[thread.lock.shared.cons]]</a>
566
 
567
  ``` cpp
568
  shared_lock() noexcept;
 
580
  mode.
581
 
582
  *Effects:* Constructs an object of type `shared_lock` and calls
583
  `m.lock_shared()`.
584
 
585
+ *Postconditions:* `pm == addressof(m)` and `owns == true`.
586
 
587
  ``` cpp
588
  shared_lock(mutex_type& m, defer_lock_t) noexcept;
589
  ```
590
 
591
  *Effects:* Constructs an object of type `shared_lock`.
592
 
593
+ *Postconditions:* `pm == addressof(m)` and `owns == false`.
594
 
595
  ``` cpp
596
  shared_lock(mutex_type& m, try_to_lock_t);
597
  ```
598
 
 
600
  mode.
601
 
602
  *Effects:* Constructs an object of type `shared_lock` and calls
603
  `m.try_lock_shared()`.
604
 
605
+ *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
606
+ the value returned by the call to `m.try_lock_shared()`.
607
 
608
  ``` cpp
609
  shared_lock(mutex_type& m, adopt_lock_t);
610
  ```
611
 
612
  *Requires:* The calling thread has shared ownership of the mutex.
613
 
614
  *Effects:* Constructs an object of type `shared_lock`.
615
 
616
+ *Postconditions:* `pm == addressof(m)` and `owns == true`.
617
 
618
  ``` cpp
619
  template <class Clock, class Duration>
620
  shared_lock(mutex_type& m,
621
  const chrono::time_point<Clock, Duration>& abs_time);
 
625
  mode.
626
 
627
  *Effects:* Constructs an object of type `shared_lock` and calls
628
  `m.try_lock_shared_until(abs_time)`.
629
 
630
+ *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
631
+ the value returned by the call to `m.try_lock_shared_until(abs_time)`.
632
 
633
  ``` cpp
634
  template <class Rep, class Period>
635
  shared_lock(mutex_type& m,
636
  const chrono::duration<Rep, Period>& rel_time);
 
640
  mode.
641
 
642
  *Effects:* Constructs an object of type `shared_lock` and calls
643
  `m.try_lock_shared_for(rel_time)`.
644
 
645
+ *Postconditions:* `pm == addressof(m)` and `owns == res` where `res` is
646
+ the value returned by the call to `m.try_lock_shared_for(rel_time)`.
647
 
648
  ``` cpp
649
  ~shared_lock();
650
  ```
651
 
 
653
 
654
  ``` cpp
655
  shared_lock(shared_lock&& sl) noexcept;
656
  ```
657
 
658
+ *Postconditions:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
659
  is the state of `sl` just prior to this construction),
660
  `sl.pm == nullptr` and `sl.owns == false`.
661
 
662
  ``` cpp
663
  shared_lock& operator=(shared_lock&& sl) noexcept;
664
  ```
665
 
666
  *Effects:* If `owns` calls `pm->unlock_shared()`.
667
 
668
+ *Postconditions:* `pm == sl_p.pm` and `owns == sl_p.owns` (where `sl_p`
669
  is the state of `sl` just prior to this assignment), `sl.pm == nullptr`
670
  and `sl.owns == false`.
671
 
672
  ##### `shared_lock` locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
673
 
674
  ``` cpp
675
  void lock();
676
  ```
677
 
678
+ *Effects:* As if by `pm->lock_shared()`.
679
 
680
  *Postconditions:* `owns == true`.
681
 
682
+ *Throws:* Any exception thrown by `pm->lock_shared()`. `system_error`
683
+ when an exception is required ([[thread.req.exception]]).
684
+
685
+ *Error conditions:*
686
+
687
+ - `operation_not_permitted` — if `pm` is `nullptr`.
688
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
689
 
690
  ``` cpp
691
  bool try_lock();
692
  ```
693
 
694
+ *Effects:* As if by `pm->try_lock_shared()`.
695
 
696
  *Returns:* The value returned by the call to `pm->try_lock_shared()`.
697
 
698
  *Postconditions:* `owns == res`, where `res` is the value returned by
699
  the call to `pm->try_lock_shared()`.
700
 
701
  *Throws:* Any exception thrown by `pm->try_lock_shared()`.
702
+ `system_error` when an exception is
703
+ required ([[thread.req.exception]]).
704
+
705
+ *Error conditions:*
706
+
707
+ - `operation_not_permitted` — if `pm` is `nullptr`.
708
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
709
 
710
  ``` cpp
711
  template <class Clock, class Duration>
712
  bool
713
  try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
714
  ```
715
 
716
+ *Effects:* As if by `pm->try_lock_shared_until(abs_time)`.
717
 
718
  *Returns:* The value returned by the call to
719
  `pm->try_lock_shared_until(abs_time)`.
720
 
721
  *Postconditions:* `owns == res`, where `res` is the value returned by
722
  the call to `pm->try_lock_shared_until(abs_time)`.
723
 
724
  *Throws:* Any exception thrown by `pm->try_lock_shared_until(abs_time)`.
725
+ `system_error` when an exception is
726
+ required ([[thread.req.exception]]).
727
+
728
+ *Error conditions:*
729
+
730
+ - `operation_not_permitted` — if `pm` is `nullptr`.
731
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
732
 
733
  ``` cpp
734
  template <class Rep, class Period>
735
  bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
736
  ```
737
 
738
+ *Effects:* As if by `pm->try_lock_shared_for(rel_time)`.
739
 
740
  *Returns:* The value returned by the call to
741
  `pm->try_lock_shared_for(rel_time)`.
742
 
743
  *Postconditions:* `owns == res`, where `res` is the value returned by
744
  the call to `pm->try_lock_shared_for(rel_time)`.
745
 
746
  *Throws:* Any exception thrown by `pm->try_lock_shared_for(rel_time)`.
747
+ `system_error` when an exception is
748
+ required ([[thread.req.exception]]).
749
+
750
+ *Error conditions:*
751
+
752
+ - `operation_not_permitted` — if `pm` is `nullptr`.
753
+ - `resource_deadlock_would_occur` — if on entry `owns` is `true`.
754
 
755
  ``` cpp
756
  void unlock();
757
  ```
758
 
759
+ *Effects:* As if by `pm->unlock_shared()`.
760
 
761
  *Postconditions:* `owns == false`.
762
 
763
+ *Throws:* `system_error` when an exception is
764
+ required ([[thread.req.exception]]).
765
 
766
  *Error conditions:*
767
 
768
  - `operation_not_permitted` — if on entry `owns` is `false`.
769
 
 
786
  ``` cpp
787
  template <class Mutex>
788
  void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
789
  ```
790
 
791
+ *Effects:* As if by `x.swap(y)`.
792
 
793
  ##### `shared_lock` observers <a id="thread.lock.shared.obs">[[thread.lock.shared.obs]]</a>
794
 
795
  ``` cpp
796
  bool owns_lock() const noexcept;