tmp/tmp0a_rdupc/{from.md → to.md}
RENAMED
|
@@ -12,11 +12,11 @@ race-free programs [[intro.multithread]].
|
|
| 12 |
namespace std {
|
| 13 |
// [thread.mutex.class], class mutex
|
| 14 |
class mutex;
|
| 15 |
// [thread.mutex.recursive], class recursive_mutex
|
| 16 |
class recursive_mutex;
|
| 17 |
-
// [thread.timedmutex.class] class timed_mutex
|
| 18 |
class timed_mutex;
|
| 19 |
// [thread.timedmutex.recursive], class recursive_timed_mutex
|
| 20 |
class recursive_timed_mutex;
|
| 21 |
|
| 22 |
struct defer_lock_t { explicit defer_lock_t() = default; };
|
|
@@ -61,11 +61,11 @@ namespace std {
|
|
| 61 |
}
|
| 62 |
```
|
| 63 |
|
| 64 |
### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
|
| 65 |
|
| 66 |
-
####
|
| 67 |
|
| 68 |
A mutex object facilitates protection against data races and allows safe
|
| 69 |
synchronization of data between execution agents
|
| 70 |
[[thread.req.lockable]]. An execution agent *owns* a mutex from the time
|
| 71 |
it successfully calls one of the lock functions until it calls unlock.
|
|
@@ -219,13 +219,13 @@ another thread to acquire ownership of that object will fail (for
|
|
| 219 |
released ownership with a call to `unlock()`.
|
| 220 |
|
| 221 |
[*Note 4*: After a thread `A` has called `unlock()`, releasing a mutex,
|
| 222 |
it is possible for another thread `B` to lock the same mutex, observe
|
| 223 |
that it is no longer in use, unlock it, and destroy it, before thread
|
| 224 |
-
`A` appears to have returned from its unlock call.
|
| 225 |
-
|
| 226 |
-
|
| 227 |
typically occur when a reference-counted object contains a mutex that is
|
| 228 |
used to protect the reference count. — *end note*]
|
| 229 |
|
| 230 |
The class `mutex` meets all of the mutex requirements
|
| 231 |
[[thread.mutex.requirements]]. It is a standard-layout class
|
|
@@ -281,11 +281,11 @@ ownership for a `recursive_mutex` object, additional calls to
|
|
| 281 |
of type `system_error`. A thread shall call `unlock()` once for each
|
| 282 |
level of ownership acquired by calls to `lock()` and `try_lock()`. Only
|
| 283 |
when all levels of ownership have been released may ownership be
|
| 284 |
acquired by another thread.
|
| 285 |
|
| 286 |
-
The behavior of a program is undefined if
|
| 287 |
|
| 288 |
- it destroys a `recursive_mutex` object owned by any thread or
|
| 289 |
- a thread terminates while owning a `recursive_mutex` object.
|
| 290 |
|
| 291 |
#### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
|
|
@@ -392,11 +392,11 @@ a call to `unlock()` or the call to `try_lock_for()` or
|
|
| 392 |
|
| 393 |
The class `timed_mutex` meets all of the timed mutex requirements
|
| 394 |
[[thread.timedmutex.requirements]]. It is a standard-layout class
|
| 395 |
[[class.prop]].
|
| 396 |
|
| 397 |
-
The behavior of a program is undefined if
|
| 398 |
|
| 399 |
- it destroys a `timed_mutex` object owned by any thread,
|
| 400 |
- a thread that owns a `timed_mutex` object calls `lock()`,
|
| 401 |
`try_lock()`, `try_lock_for()`, or `try_lock_until()` on that object,
|
| 402 |
or
|
|
@@ -451,11 +451,11 @@ for a `recursive_timed_mutex` object, additional calls to `try_lock()`,
|
|
| 451 |
`unlock()` once for each level of ownership acquired by calls to
|
| 452 |
`lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`. Only
|
| 453 |
when all levels of ownership have been released may ownership of the
|
| 454 |
object be acquired by another thread.
|
| 455 |
|
| 456 |
-
The behavior of a program is undefined if
|
| 457 |
|
| 458 |
- it destroys a `recursive_timed_mutex` object owned by any thread, or
|
| 459 |
- a thread terminates while owning a `recursive_timed_mutex` object.
|
| 460 |
|
| 461 |
#### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
|
|
@@ -580,11 +580,11 @@ ownership semantics.
|
|
| 580 |
|
| 581 |
The class `shared_mutex` meets all of the shared mutex requirements
|
| 582 |
[[thread.sharedmutex.requirements]]. It is a standard-layout class
|
| 583 |
[[class.prop]].
|
| 584 |
|
| 585 |
-
The behavior of a program is undefined if
|
| 586 |
|
| 587 |
- it destroys a `shared_mutex` object owned by any thread,
|
| 588 |
- a thread attempts to recursively gain any ownership of a
|
| 589 |
`shared_mutex`, or
|
| 590 |
- a thread terminates while possessing any ownership of a
|
|
@@ -706,11 +706,11 @@ shared ownership semantics.
|
|
| 706 |
|
| 707 |
The class `shared_timed_mutex` meets all of the shared timed mutex
|
| 708 |
requirements [[thread.sharedtimedmutex.requirements]]. It is a
|
| 709 |
standard-layout class [[class.prop]].
|
| 710 |
|
| 711 |
-
The behavior of a program is undefined if
|
| 712 |
|
| 713 |
- it destroys a `shared_timed_mutex` object owned by any thread,
|
| 714 |
- a thread attempts to recursively gain any ownership of a
|
| 715 |
`shared_timed_mutex`, or
|
| 716 |
- a thread terminates while possessing any ownership of a
|
|
@@ -890,11 +890,11 @@ namespace std {
|
|
| 890 |
|
| 891 |
unique_lock(const unique_lock&) = delete;
|
| 892 |
unique_lock& operator=(const unique_lock&) = delete;
|
| 893 |
|
| 894 |
unique_lock(unique_lock&& u) noexcept;
|
| 895 |
-
unique_lock& operator=(unique_lock&& u);
|
| 896 |
|
| 897 |
// [thread.lock.unique.locking], locking
|
| 898 |
void lock();
|
| 899 |
bool try_lock();
|
| 900 |
|
|
@@ -1016,24 +1016,16 @@ unique_lock(unique_lock&& u) noexcept;
|
|
| 1016 |
*Ensures:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is the
|
| 1017 |
state of `u` just prior to this construction), `u.pm == 0` and
|
| 1018 |
`u.owns == false`.
|
| 1019 |
|
| 1020 |
``` cpp
|
| 1021 |
-
unique_lock& operator=(unique_lock&& u);
|
| 1022 |
```
|
| 1023 |
|
| 1024 |
-
*Effects:*
|
| 1025 |
|
| 1026 |
-
*
|
| 1027 |
-
state of `u` just prior to this construction), `u.pm == 0` and
|
| 1028 |
-
`u.owns == false`.
|
| 1029 |
-
|
| 1030 |
-
[*Note 1*: With a recursive mutex it is possible for both `*this` and
|
| 1031 |
-
`u` to own the same mutex before the assignment. In this case, `*this`
|
| 1032 |
-
will own the mutex after the assignment and `u` will not. — *end note*]
|
| 1033 |
-
|
| 1034 |
-
*Throws:* Nothing.
|
| 1035 |
|
| 1036 |
``` cpp
|
| 1037 |
~unique_lock();
|
| 1038 |
```
|
| 1039 |
|
|
@@ -1338,15 +1330,13 @@ state of `sl` just prior to this construction), `sl.pm == nullptr` and
|
|
| 1338 |
|
| 1339 |
``` cpp
|
| 1340 |
shared_lock& operator=(shared_lock&& sl) noexcept;
|
| 1341 |
```
|
| 1342 |
|
| 1343 |
-
*Effects:*
|
| 1344 |
|
| 1345 |
-
*
|
| 1346 |
-
state of `sl` just prior to this assignment), `sl.pm == nullptr` and
|
| 1347 |
-
`sl.owns == false`.
|
| 1348 |
|
| 1349 |
##### Locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
|
| 1350 |
|
| 1351 |
``` cpp
|
| 1352 |
void lock();
|
|
@@ -1571,11 +1561,11 @@ template<class Callable, class... Args>
|
|
| 1571 |
|
| 1572 |
*Mandates:* `is_invocable_v<Callable, Args...>` is `true`.
|
| 1573 |
|
| 1574 |
*Effects:* An execution of `call_once` that does not call its `func` is
|
| 1575 |
a *passive* execution. An execution of `call_once` that calls its `func`
|
| 1576 |
-
is an *active* execution. An active execution
|
| 1577 |
std::forward\<Callable\>(func),
|
| 1578 |
std::forward\<Args\>(args)...) [[func.require]]. If such a call to
|
| 1579 |
`func` throws an exception the execution is *exceptional*, otherwise it
|
| 1580 |
is *returning*. An exceptional execution propagates the exception to the
|
| 1581 |
caller of `call_once`. Among all executions of `call_once` for any given
|
|
|
|
| 12 |
namespace std {
|
| 13 |
// [thread.mutex.class], class mutex
|
| 14 |
class mutex;
|
| 15 |
// [thread.mutex.recursive], class recursive_mutex
|
| 16 |
class recursive_mutex;
|
| 17 |
+
// [thread.timedmutex.class], class timed_mutex
|
| 18 |
class timed_mutex;
|
| 19 |
// [thread.timedmutex.recursive], class recursive_timed_mutex
|
| 20 |
class recursive_timed_mutex;
|
| 21 |
|
| 22 |
struct defer_lock_t { explicit defer_lock_t() = default; };
|
|
|
|
| 61 |
}
|
| 62 |
```
|
| 63 |
|
| 64 |
### Mutex requirements <a id="thread.mutex.requirements">[[thread.mutex.requirements]]</a>
|
| 65 |
|
| 66 |
+
#### General <a id="thread.mutex.requirements.general">[[thread.mutex.requirements.general]]</a>
|
| 67 |
|
| 68 |
A mutex object facilitates protection against data races and allows safe
|
| 69 |
synchronization of data between execution agents
|
| 70 |
[[thread.req.lockable]]. An execution agent *owns* a mutex from the time
|
| 71 |
it successfully calls one of the lock functions until it calls unlock.
|
|
|
|
| 219 |
released ownership with a call to `unlock()`.
|
| 220 |
|
| 221 |
[*Note 4*: After a thread `A` has called `unlock()`, releasing a mutex,
|
| 222 |
it is possible for another thread `B` to lock the same mutex, observe
|
| 223 |
that it is no longer in use, unlock it, and destroy it, before thread
|
| 224 |
+
`A` appears to have returned from its unlock call. Conforming
|
| 225 |
+
implementations handle such scenarios correctly, as long as thread `A`
|
| 226 |
+
does not access the mutex after the unlock call returns. These cases
|
| 227 |
typically occur when a reference-counted object contains a mutex that is
|
| 228 |
used to protect the reference count. — *end note*]
|
| 229 |
|
| 230 |
The class `mutex` meets all of the mutex requirements
|
| 231 |
[[thread.mutex.requirements]]. It is a standard-layout class
|
|
|
|
| 281 |
of type `system_error`. A thread shall call `unlock()` once for each
|
| 282 |
level of ownership acquired by calls to `lock()` and `try_lock()`. Only
|
| 283 |
when all levels of ownership have been released may ownership be
|
| 284 |
acquired by another thread.
|
| 285 |
|
| 286 |
+
The behavior of a program is undefined if
|
| 287 |
|
| 288 |
- it destroys a `recursive_mutex` object owned by any thread or
|
| 289 |
- a thread terminates while owning a `recursive_mutex` object.
|
| 290 |
|
| 291 |
#### Timed mutex types <a id="thread.timedmutex.requirements">[[thread.timedmutex.requirements]]</a>
|
|
|
|
| 392 |
|
| 393 |
The class `timed_mutex` meets all of the timed mutex requirements
|
| 394 |
[[thread.timedmutex.requirements]]. It is a standard-layout class
|
| 395 |
[[class.prop]].
|
| 396 |
|
| 397 |
+
The behavior of a program is undefined if
|
| 398 |
|
| 399 |
- it destroys a `timed_mutex` object owned by any thread,
|
| 400 |
- a thread that owns a `timed_mutex` object calls `lock()`,
|
| 401 |
`try_lock()`, `try_lock_for()`, or `try_lock_until()` on that object,
|
| 402 |
or
|
|
|
|
| 451 |
`unlock()` once for each level of ownership acquired by calls to
|
| 452 |
`lock()`, `try_lock()`, `try_lock_for()`, and `try_lock_until()`. Only
|
| 453 |
when all levels of ownership have been released may ownership of the
|
| 454 |
object be acquired by another thread.
|
| 455 |
|
| 456 |
+
The behavior of a program is undefined if
|
| 457 |
|
| 458 |
- it destroys a `recursive_timed_mutex` object owned by any thread, or
|
| 459 |
- a thread terminates while owning a `recursive_timed_mutex` object.
|
| 460 |
|
| 461 |
#### Shared mutex types <a id="thread.sharedmutex.requirements">[[thread.sharedmutex.requirements]]</a>
|
|
|
|
| 580 |
|
| 581 |
The class `shared_mutex` meets all of the shared mutex requirements
|
| 582 |
[[thread.sharedmutex.requirements]]. It is a standard-layout class
|
| 583 |
[[class.prop]].
|
| 584 |
|
| 585 |
+
The behavior of a program is undefined if
|
| 586 |
|
| 587 |
- it destroys a `shared_mutex` object owned by any thread,
|
| 588 |
- a thread attempts to recursively gain any ownership of a
|
| 589 |
`shared_mutex`, or
|
| 590 |
- a thread terminates while possessing any ownership of a
|
|
|
|
| 706 |
|
| 707 |
The class `shared_timed_mutex` meets all of the shared timed mutex
|
| 708 |
requirements [[thread.sharedtimedmutex.requirements]]. It is a
|
| 709 |
standard-layout class [[class.prop]].
|
| 710 |
|
| 711 |
+
The behavior of a program is undefined if
|
| 712 |
|
| 713 |
- it destroys a `shared_timed_mutex` object owned by any thread,
|
| 714 |
- a thread attempts to recursively gain any ownership of a
|
| 715 |
`shared_timed_mutex`, or
|
| 716 |
- a thread terminates while possessing any ownership of a
|
|
|
|
| 890 |
|
| 891 |
unique_lock(const unique_lock&) = delete;
|
| 892 |
unique_lock& operator=(const unique_lock&) = delete;
|
| 893 |
|
| 894 |
unique_lock(unique_lock&& u) noexcept;
|
| 895 |
+
unique_lock& operator=(unique_lock&& u) noexcept;
|
| 896 |
|
| 897 |
// [thread.lock.unique.locking], locking
|
| 898 |
void lock();
|
| 899 |
bool try_lock();
|
| 900 |
|
|
|
|
| 1016 |
*Ensures:* `pm == u_p.pm` and `owns == u_p.owns` (where `u_p` is the
|
| 1017 |
state of `u` just prior to this construction), `u.pm == 0` and
|
| 1018 |
`u.owns == false`.
|
| 1019 |
|
| 1020 |
``` cpp
|
| 1021 |
+
unique_lock& operator=(unique_lock&& u) noexcept;
|
| 1022 |
```
|
| 1023 |
|
| 1024 |
+
*Effects:* Equivalent to: `unique_lock(std::move(u)).swap(*this)`
|
| 1025 |
|
| 1026 |
+
*Returns:* `*this`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1027 |
|
| 1028 |
``` cpp
|
| 1029 |
~unique_lock();
|
| 1030 |
```
|
| 1031 |
|
|
|
|
| 1330 |
|
| 1331 |
``` cpp
|
| 1332 |
shared_lock& operator=(shared_lock&& sl) noexcept;
|
| 1333 |
```
|
| 1334 |
|
| 1335 |
+
*Effects:* Equivalent to: `shared_lock(std::move(sl)).swap(*this)`
|
| 1336 |
|
| 1337 |
+
*Returns:* `*this`.
|
|
|
|
|
|
|
| 1338 |
|
| 1339 |
##### Locking <a id="thread.lock.shared.locking">[[thread.lock.shared.locking]]</a>
|
| 1340 |
|
| 1341 |
``` cpp
|
| 1342 |
void lock();
|
|
|
|
| 1561 |
|
| 1562 |
*Mandates:* `is_invocable_v<Callable, Args...>` is `true`.
|
| 1563 |
|
| 1564 |
*Effects:* An execution of `call_once` that does not call its `func` is
|
| 1565 |
a *passive* execution. An execution of `call_once` that calls its `func`
|
| 1566 |
+
is an *active* execution. An active execution evaluates *INVOKE*(
|
| 1567 |
std::forward\<Callable\>(func),
|
| 1568 |
std::forward\<Args\>(args)...) [[func.require]]. If such a call to
|
| 1569 |
`func` throws an exception the execution is *exceptional*, otherwise it
|
| 1570 |
is *returning*. An exceptional execution propagates the exception to the
|
| 1571 |
caller of `call_once`. Among all executions of `call_once` for any given
|