Files
2025-10-25 03:02:53 +03:00

2547 lines
116 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[thread.mutex]
# 32 Concurrency support library [[thread]](./#thread)
## 32.6 Mutual exclusion [thread.mutex]
### [32.6.1](#general) General [[thread.mutex.general]](thread.mutex.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7252)
Subclause [thread.mutex] provides mechanisms for mutual exclusion: mutexes, locks, and call
once[.](#general-1.sentence-1)
These mechanisms ease the production of race-free
programs ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#general-1.sentence-2)
### [32.6.2](#mutex.syn) Header <mutex> synopsis [[mutex.syn]](mutex.syn)
[🔗](#header:%3cmutex%3e)
namespace std {// [[thread.mutex.class]](#class "32.6.4.2.2Class mutex"), class mutexclass mutex; // [[thread.mutex.recursive]](#recursive "32.6.4.2.3Class recursive_­mutex"), class recursive_mutexclass recursive_mutex; // [[thread.timedmutex.class]](#thread.timedmutex.class "32.6.4.3.2Class timed_­mutex"), class timed_mutexclass timed_mutex; // [[thread.timedmutex.recursive]](#thread.timedmutex.recursive "32.6.4.3.3Class recursive_­timed_­mutex"), class recursive_timed_mutexclass recursive_timed_mutex; struct defer_lock_t { explicit defer_lock_t() = default; }; struct try_to_lock_t { explicit try_to_lock_t() = default; }; struct adopt_lock_t { explicit adopt_lock_t() = default; }; inline constexpr defer_lock_t defer_lock { }; inline constexpr try_to_lock_t try_to_lock { }; inline constexpr adopt_lock_t adopt_lock { }; // [[thread.lock]](#thread.lock "32.6.5Locks"), lockstemplate<class Mutex> class lock_guard; template<class... MutexTypes> class scoped_lock; template<class Mutex> class unique_lock; template<class Mutex>void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; // [[thread.lock.algorithm]](#thread.lock.algorithm "32.6.6Generic locking algorithms"), generic locking algorithmstemplate<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...); template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); struct once_flag; template<class Callable, class... Args>void call_once(once_flag& flag, Callable&& func, Args&&... args);}
### [32.6.3](#shared.mutex.syn) Header <shared_mutex> synopsis [[shared.mutex.syn]](shared.mutex.syn)
[🔗](#header:%3cshared_mutex%3e)
namespace std {// [[thread.sharedmutex.class]](#thread.sharedmutex.class "32.6.4.4.2Class shared_­mutex"), class shared_mutexclass shared_mutex; // [[thread.sharedtimedmutex.class]](#thread.sharedtimedmutex.class "32.6.4.5.2Class shared_­timed_­mutex"), class shared_timed_mutexclass shared_timed_mutex; // [[thread.lock.shared]](#thread.lock.shared "32.6.5.5Class template shared_­lock"), class template shared_locktemplate<class Mutex> class shared_lock; template<class Mutex>void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;}
### [32.6.4](#requirements) Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements)
#### [32.6.4.1](#requirements.general) General [[thread.mutex.requirements.general]](thread.mutex.requirements.general)
[1](#requirements.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7318)
A mutex object facilitates protection against data races and allows safe synchronization of
data between [execution agents](thread.req.lockable#def:execution_agent "32.2.5Requirements for Cpp17Lockable types[thread.req.lockable]")[.](#requirements.general-1.sentence-1)
An execution agent [*owns*](#def:owns) a mutex from the time it successfully calls one of the
lock functions until it calls unlock[.](#requirements.general-1.sentence-2)
Mutexes can be either recursive or non-recursive, and can
grant simultaneous ownership to one or many execution agents[.](#requirements.general-1.sentence-3)
Both
recursive and non-recursive mutexes are supplied[.](#requirements.general-1.sentence-4)
#### [32.6.4.2](#requirements.mutex) Mutex types [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex)
#### [32.6.4.2.1](#requirements.mutex.general) General [[thread.mutex.requirements.mutex.general]](thread.mutex.requirements.mutex.general)
[1](#requirements.mutex.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7330)
The [*mutex types*](#def:mutex_types "32.6.4.2.1General[thread.mutex.requirements.mutex.general]") are the standard library types mutex,recursive_mutex, timed_mutex, recursive_timed_mutex,shared_mutex, and shared_timed_mutex[.](#requirements.mutex.general-1.sentence-1)
They meet the requirements set out in [[thread.mutex.requirements.mutex]](#requirements.mutex "32.6.4.2Mutex types")[.](#requirements.mutex.general-1.sentence-2)
In this description, m denotes an object of a mutex type[.](#requirements.mutex.general-1.sentence-3)
[*Note [1](#requirements.mutex.general-note-1)*:
The mutex types meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#requirements.mutex.general-1.sentence-4)
— *end note*]
[2](#requirements.mutex.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7340)
The mutex types meet [*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]")[.](#requirements.mutex.general-2.sentence-1)
If initialization of an object of a mutex type fails,
an exception of type system_error is thrown[.](#requirements.mutex.general-2.sentence-2)
The mutex types are neither copyable nor movable[.](#requirements.mutex.general-2.sentence-3)
[3](#requirements.mutex.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7346)
The error conditions for error codes, if any, reported by member functions of the mutex types
are as follows:
- [(3.1)](#requirements.mutex.general-3.1)
resource_unavailable_try_again — if any native handle type manipulated is not available[.](#requirements.mutex.general-3.1.sentence-1)
- [(3.2)](#requirements.mutex.general-3.2)
operation_not_permitted — if the thread does not have the
privilege to perform the operation[.](#requirements.mutex.general-3.2.sentence-1)
- [(3.3)](#requirements.mutex.general-3.3)
invalid_argument — if any native handle type manipulated as part of mutex
construction is incorrect[.](#requirements.mutex.general-3.3.sentence-1)
[4](#requirements.mutex.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7357)
The implementation provides lock and unlock operations, as described below[.](#requirements.mutex.general-4.sentence-1)
For purposes of determining the existence of a data race, these behave as
atomic operations ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))[.](#requirements.mutex.general-4.sentence-2)
The lock and unlock operations on
a single mutex appears to occur in a single total order[.](#requirements.mutex.general-4.sentence-3)
[*Note [2](#requirements.mutex.general-note-2)*:
This
can be viewed as the [modification order](intro.multithread#def:modification_order "6.10.2Multi-threaded executions and data races[intro.multithread]") of the
mutex[.](#requirements.mutex.general-4.sentence-4)
— *end note*]
[*Note [3](#requirements.mutex.general-note-3)*:
Construction and
destruction of an object of a mutex type need not be thread-safe; other
synchronization can be used to ensure that mutex objects are initialized
and visible to other threads[.](#requirements.mutex.general-4.sentence-5)
— *end note*]
[5](#requirements.mutex.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7374)
The expression m.lock() is well-formed and has the following semantics:
[6](#requirements.mutex.general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7377)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#requirements.mutex.general-6.sentence-1)
[7](#requirements.mutex.general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7383)
*Effects*: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread[.](#requirements.mutex.general-7.sentence-1)
[8](#requirements.mutex.general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7388)
*Synchronization*: Prior unlock() operations on the same object[*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#requirements.mutex.general-8.sentence-1)
[9](#requirements.mutex.general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7393)
*Postconditions*: The calling thread owns the mutex[.](#requirements.mutex.general-9.sentence-1)
[10](#requirements.mutex.general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7397)
*Return type*: void[.](#requirements.mutex.general-10.sentence-1)
[11](#requirements.mutex.general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7400)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#requirements.mutex.general-11.sentence-1)
[12](#requirements.mutex.general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7405)
*Error conditions*:
- [(12.1)](#requirements.mutex.general-12.1)
operation_not_permitted — if the thread does not have the
privilege to perform the operation[.](#requirements.mutex.general-12.1.sentence-1)
- [(12.2)](#requirements.mutex.general-12.2)
resource_deadlock_would_occur — if the implementation detects
that a deadlock would occur[.](#requirements.mutex.general-12.2.sentence-1)
[13](#requirements.mutex.general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7416)
The expression m.try_lock() is well-formed and has the following semantics:
[14](#requirements.mutex.general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7419)
*Preconditions*: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex[.](#requirements.mutex.general-14.sentence-1)
[15](#requirements.mutex.general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7425)
*Effects*: Attempts to obtain ownership of the mutex for the calling thread without
blocking[.](#requirements.mutex.general-15.sentence-1)
If ownership is not obtained, there is no effect and try_lock() immediately returns[.](#requirements.mutex.general-15.sentence-2)
An implementation may fail to obtain the lock even if it is not
held by any other thread[.](#requirements.mutex.general-15.sentence-3)
[*Note [4](#requirements.mutex.general-note-4)*:
This spurious failure is normally uncommon, but
allows interesting implementations based on a simple
compare and exchange ([[atomics]](atomics "32.5Atomic operations"))[.](#requirements.mutex.general-15.sentence-4)
— *end note*]
An implementation should ensure that try_lock() does not consistently return false in the absence of contending mutex acquisitions[.](#requirements.mutex.general-15.sentence-5)
[16](#requirements.mutex.general-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7439)
*Synchronization*: If try_lock() returns true, prior unlock() operations
on the same object [synchronize with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") this operation[.](#requirements.mutex.general-16.sentence-1)
[*Note [5](#requirements.mutex.general-note-5)*:
Since lock() does not synchronize with a failed subsequenttry_lock(), the visibility rules are weak enough that little would be
known about the state after a failure, even in the absence of spurious failures[.](#requirements.mutex.general-16.sentence-2)
— *end note*]
[17](#requirements.mutex.general-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7449)
*Return type*: bool[.](#requirements.mutex.general-17.sentence-1)
[18](#requirements.mutex.general-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7452)
*Returns*: true if ownership was obtained, otherwise false[.](#requirements.mutex.general-18.sentence-1)
[19](#requirements.mutex.general-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7456)
*Throws*: Nothing[.](#requirements.mutex.general-19.sentence-1)
[20](#requirements.mutex.general-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7461)
The expression m.unlock() is well-formed and has the following semantics:
[21](#requirements.mutex.general-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7464)
*Preconditions*: The calling thread owns the mutex[.](#requirements.mutex.general-21.sentence-1)
[22](#requirements.mutex.general-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7468)
*Effects*: Releases the calling thread's ownership of the mutex[.](#requirements.mutex.general-22.sentence-1)
[23](#requirements.mutex.general-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7472)
*Return type*: void[.](#requirements.mutex.general-23.sentence-1)
[24](#requirements.mutex.general-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7475)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequent
lock operations that obtain ownership on the same object[.](#requirements.mutex.general-24.sentence-1)
[25](#requirements.mutex.general-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7480)
*Throws*: Nothing[.](#requirements.mutex.general-25.sentence-1)
#### [32.6.4.2.2](#class) Class mutex [[thread.mutex.class]](thread.mutex.class)
[🔗](#lib:mutex)
namespace std {class mutex {public:constexpr mutex() noexcept; ~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7508)
The class mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#class-1.sentence-1)
If one thread owns a mutex object, attempts by another thread to acquire
ownership of that object will fail (for try_lock()) or block (forlock()) until the owning thread has released ownership with a call tounlock()[.](#class-1.sentence-2)
[2](#class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7516)
[*Note [1](#class-note-1)*:
After a thread A has called unlock(), releasing a mutex, it is possible for another
thread B to lock the same mutex, observe that it is no longer in use, unlock it, and
destroy it, before thread A appears to have returned from its unlock call[.](#class-2.sentence-1)
Conforming implementations
handle such scenarios correctly, as long as thread A does not access the
mutex after the unlock call returns[.](#class-2.sentence-2)
These cases typically occur when a reference-counted object
contains a mutex that is used to protect the reference count[.](#class-2.sentence-3)
— *end note*]
[3](#class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7526)
The class mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](#requirements "32.6.4Mutex requirements"))[.](#class-3.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#class-3.sentence-2)
[4](#class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7531)
[*Note [2](#class-note-2)*:
A program can deadlock if the thread that owns a mutex object callslock() on that object[.](#class-4.sentence-1)
If the implementation can detect the deadlock,
a resource_deadlock_would_occur error condition might be observed[.](#class-4.sentence-2)
— *end note*]
[5](#class-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7538)
The behavior of a program is undefined if
it destroys a mutex object owned by any thread or
a thread terminates while owning a mutex object[.](#class-5.sentence-1)
#### [32.6.4.2.3](#recursive) Class recursive_mutex [[thread.mutex.recursive]](thread.mutex.recursive)
[🔗](#lib:recursive_mutex)
namespace std {class recursive_mutex {public: recursive_mutex(); ~recursive_mutex();
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock() noexcept; void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#recursive-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7566)
The class recursive_mutex provides a recursive mutex with exclusive ownership
semantics[.](#recursive-1.sentence-1)
If one thread owns a recursive_mutex object, attempts by another
thread to acquire ownership of that object will fail (for try_lock()) or block
(for lock()) until the first thread has completely released ownership[.](#recursive-1.sentence-2)
[2](#recursive-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7573)
The class recursive_mutex meets
all of the mutex requirements ([[thread.mutex.requirements]](#requirements "32.6.4Mutex requirements"))[.](#recursive-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#recursive-2.sentence-2)
[3](#recursive-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7578)
A thread that owns a recursive_mutex object may acquire additional levels of
ownership by calling lock() or try_lock() on that object[.](#recursive-3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#recursive-3.sentence-2)
If a thread
has already acquired the maximum level of ownership for a recursive_mutex object, additional calls to try_lock() fail, and additional calls tolock() throw an exception of type system_error[.](#recursive-3.sentence-3)
A thread
shall call unlock() once for each level of ownership acquired by calls tolock() and try_lock()[.](#recursive-3.sentence-4)
Only when all levels of ownership have been
released may ownership be acquired by another thread[.](#recursive-3.sentence-5)
[4](#recursive-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7589)
The behavior of a program is undefined if
- [(4.1)](#recursive-4.1)
it destroys a recursive_mutex object owned by any thread or
- [(4.2)](#recursive-4.2)
a thread terminates while owning a recursive_mutex object[.](#recursive-4.sentence-1)
#### [32.6.4.3](#thread.timedmutex.requirements) Timed mutex types [[thread.timedmutex.requirements]](thread.timedmutex.requirements)
#### [32.6.4.3.1](#thread.timedmutex.requirements.general) General [[thread.timedmutex.requirements.general]](thread.timedmutex.requirements.general)
[1](#thread.timedmutex.requirements.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7600)
The [*timed mutex types*](#def:timed_mutex_types "32.6.4.3.1General[thread.timedmutex.requirements.general]") are the standard library types timed_mutex,recursive_timed_mutex, and shared_timed_mutex[.](#thread.timedmutex.requirements.general-1.sentence-1)
They
meet the requirements set out below[.](#thread.timedmutex.requirements.general-1.sentence-2)
In this description, m denotes an object of a mutex type,rel_time denotes an object of an
instantiation of [duration](time.duration "30.5Class template duration[time.duration]"), and abs_time denotes an
object of an
instantiation of [time_point](time.point "30.6Class template time_­point[time.point]")[.](#thread.timedmutex.requirements.general-1.sentence-3)
[*Note [1](#thread.timedmutex.requirements.general-note-1)*:
The timed mutex types meet the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.timedmutex.requirements.general-1.sentence-4)
— *end note*]
[2](#thread.timedmutex.requirements.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7614)
The expression m.try_lock_for(rel_time) is well-formed
and has the following semantics:
[3](#thread.timedmutex.requirements.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7618)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not
own the mutex[.](#thread.timedmutex.requirements.general-3.sentence-1)
[4](#thread.timedmutex.requirements.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7624)
*Effects*: The function attempts to obtain ownership of the mutex within the
relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by rel_time[.](#thread.timedmutex.requirements.general-4.sentence-1)
If the time specified by rel_time is less than or
equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by callingtry_lock())[.](#thread.timedmutex.requirements.general-4.sentence-2)
The function returns within the timeout specified byrel_time only if it has obtained ownership of the mutex object[.](#thread.timedmutex.requirements.general-4.sentence-3)
[*Note [2](#thread.timedmutex.requirements.general-note-2)*:
As
with try_lock(), there is no guarantee that ownership will be obtained if the
lock is available, but implementations are expected to make a strong effort to do so[.](#thread.timedmutex.requirements.general-4.sentence-4)
— *end note*]
[5](#thread.timedmutex.requirements.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7638)
*Synchronization*: If try_lock_for() returns true, prior unlock() operations
on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#thread.timedmutex.requirements.general-5.sentence-1)
[6](#thread.timedmutex.requirements.general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7643)
*Return type*: bool[.](#thread.timedmutex.requirements.general-6.sentence-1)
[7](#thread.timedmutex.requirements.general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7646)
*Returns*: true if ownership was obtained, otherwise false[.](#thread.timedmutex.requirements.general-7.sentence-1)
[8](#thread.timedmutex.requirements.general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7650)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#thread.timedmutex.requirements.general-8.sentence-1)
[9](#thread.timedmutex.requirements.general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7655)
The expression m.try_lock_until(abs_time) is well-formed
and has the following semantics:
[10](#thread.timedmutex.requirements.general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7659)
*Preconditions*: If m is of type timed_mutex orshared_timed_mutex, the calling thread does not own the
mutex[.](#thread.timedmutex.requirements.general-10.sentence-1)
[11](#thread.timedmutex.requirements.general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7665)
*Effects*: The function attempts to obtain ownership of the mutex[.](#thread.timedmutex.requirements.general-11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain ownership
without blocking (as if by calling try_lock())[.](#thread.timedmutex.requirements.general-11.sentence-2)
The function
returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified byabs_time only if it has obtained ownership of the mutex object[.](#thread.timedmutex.requirements.general-11.sentence-3)
[*Note [3](#thread.timedmutex.requirements.general-note-3)*:
As with try_lock(), there is no guarantee that ownership will
be obtained if the lock is available, but implementations are expected to make a
strong effort to do so[.](#thread.timedmutex.requirements.general-11.sentence-4)
— *end note*]
[12](#thread.timedmutex.requirements.general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7678)
*Synchronization*: If try_lock_until() returns true, prior unlock() operations on the same object [*synchronize with*](#def:synchronize_with) ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races"))
this operation[.](#thread.timedmutex.requirements.general-12.sentence-1)
[13](#thread.timedmutex.requirements.general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7684)
*Return type*: bool[.](#thread.timedmutex.requirements.general-13.sentence-1)
[14](#thread.timedmutex.requirements.general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7687)
*Returns*: true if ownership was obtained, otherwise false[.](#thread.timedmutex.requirements.general-14.sentence-1)
[15](#thread.timedmutex.requirements.general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7691)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#thread.timedmutex.requirements.general-15.sentence-1)
#### [32.6.4.3.2](#thread.timedmutex.class) Class timed_mutex [[thread.timedmutex.class]](thread.timedmutex.class)
[🔗](#lib:timed_mutex)
namespace std {class timed_mutex {public: timed_mutex(); ~timed_mutex();
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete; void lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.timedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7723)
The class timed_mutex provides a non-recursive mutex with exclusive ownership
semantics[.](#thread.timedmutex.class-1.sentence-1)
If one thread owns a timed_mutex object, attempts by another thread
to acquire ownership of that object will fail (for try_lock()) or block
(for lock(), try_lock_for(), and try_lock_until()) until
the owning thread has released ownership with a call to unlock() or the
call to try_lock_for() or try_lock_until() times out (having
failed to obtain ownership)[.](#thread.timedmutex.class-1.sentence-2)
[2](#thread.timedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7733)
The class timed_mutex meets
all of the timed mutex requirements ([[thread.timedmutex.requirements]](#thread.timedmutex.requirements "32.6.4.3Timed mutex types"))[.](#thread.timedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.timedmutex.class-2.sentence-2)
[3](#thread.timedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7738)
The behavior of a program is undefined if
- [(3.1)](#thread.timedmutex.class-3.1)
it destroys a timed_mutex object owned by any thread,
- [(3.2)](#thread.timedmutex.class-3.2)
a thread that owns a timed_mutex object calls lock(),try_lock(), try_lock_for(), or try_lock_until() on that object, or
- [(3.3)](#thread.timedmutex.class-3.3)
a thread terminates while owning a timed_mutex object[.](#thread.timedmutex.class-3.sentence-1)
#### [32.6.4.3.3](#thread.timedmutex.recursive) Class recursive_timed_mutex [[thread.timedmutex.recursive]](thread.timedmutex.recursive)
[🔗](#lib:recursive_timed_mutex)
namespace std {class recursive_timed_mutex {public: recursive_timed_mutex(); ~recursive_timed_mutex();
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); // blockingbool try_lock() noexcept; template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.timedmutex.recursive-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7774)
The class recursive_timed_mutex provides a recursive mutex with exclusive
ownership semantics[.](#thread.timedmutex.recursive-1.sentence-1)
If one thread owns a recursive_timed_mutex object,
attempts by another thread to acquire ownership of that object will fail (fortry_lock()) or block (for lock(), try_lock_for(), andtry_lock_until()) until the owning thread has completely released
ownership or the call to try_lock_for() or try_lock_until() times out (having failed to obtain ownership)[.](#thread.timedmutex.recursive-1.sentence-2)
[2](#thread.timedmutex.recursive-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7784)
The class recursive_timed_mutex meets
all of the timed mutex requirements ([[thread.timedmutex.requirements]](#thread.timedmutex.requirements "32.6.4.3Timed mutex types"))[.](#thread.timedmutex.recursive-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.timedmutex.recursive-2.sentence-2)
[3](#thread.timedmutex.recursive-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7789)
A thread that owns a recursive_timed_mutex object may acquire additional
levels of ownership by calling lock(), try_lock(),try_lock_for(), or try_lock_until() on that object[.](#thread.timedmutex.recursive-3.sentence-1)
It is
unspecified how many levels of ownership may be acquired by a single thread[.](#thread.timedmutex.recursive-3.sentence-2)
If
a thread has already acquired the maximum level of ownership for arecursive_timed_mutex object, additional calls to try_lock(),try_lock_for(), or try_lock_until() fail, and additional
calls to lock() throw an exception of type system_error[.](#thread.timedmutex.recursive-3.sentence-3)
A
thread shall call unlock() once for each level of ownership acquired by
calls to lock(), try_lock(), try_lock_for(), andtry_lock_until()[.](#thread.timedmutex.recursive-3.sentence-4)
Only when all levels of ownership have been released
may ownership of the object be acquired by another thread[.](#thread.timedmutex.recursive-3.sentence-5)
[4](#thread.timedmutex.recursive-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7803)
The behavior of a program is undefined if
- [(4.1)](#thread.timedmutex.recursive-4.1)
it destroys a recursive_timed_mutex object owned by any thread, or
- [(4.2)](#thread.timedmutex.recursive-4.2)
a thread terminates while owning a recursive_timed_mutex object[.](#thread.timedmutex.recursive-4.sentence-1)
#### [32.6.4.4](#thread.sharedmutex.requirements) Shared mutex types [[thread.sharedmutex.requirements]](thread.sharedmutex.requirements)
#### [32.6.4.4.1](#thread.sharedmutex.requirements.general) General [[thread.sharedmutex.requirements.general]](thread.sharedmutex.requirements.general)
[1](#thread.sharedmutex.requirements.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7815)
The standard library types shared_mutex and shared_timed_mutex are [*shared mutex types*](#def:shared_mutex_types "32.6.4.4.1General[thread.sharedmutex.requirements.general]")[.](#thread.sharedmutex.requirements.general-1.sentence-1)
Shared mutex types meet the requirements of
mutex types ([[thread.mutex.requirements.mutex]](#requirements.mutex "32.6.4.2Mutex types")) and additionally
meet the requirements set out below[.](#thread.sharedmutex.requirements.general-1.sentence-2)
In this description,m denotes an object of a shared mutex type[.](#thread.sharedmutex.requirements.general-1.sentence-3)
[*Note [1](#thread.sharedmutex.requirements.general-note-1)*:
The shared mutex types meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#thread.sharedmutex.requirements.general-1.sentence-4)
— *end note*]
[2](#thread.sharedmutex.requirements.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7826)
In addition to the exclusive lock ownership mode specified
in [[thread.mutex.requirements.mutex]](#requirements.mutex "32.6.4.2Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1General[thread.sharedmutex.requirements.general]") ownership mode[.](#thread.sharedmutex.requirements.general-2.sentence-1)
Multiple execution agents can
simultaneously hold a shared lock ownership of a shared mutex type[.](#thread.sharedmutex.requirements.general-2.sentence-2)
But no
execution agent holds a shared lock while another execution agent holds an
exclusive lock on the same shared mutex type, and vice-versa[.](#thread.sharedmutex.requirements.general-2.sentence-3)
The maximum
number of execution agents which can share a shared lock on a single shared
mutex type is unspecified, but is at least 10000[.](#thread.sharedmutex.requirements.general-2.sentence-4)
If more than the
maximum number of execution agents attempt to obtain a shared lock, the
excess execution agents block until the number of shared locks are
reduced below the maximum amount by other execution agents releasing their
shared lock[.](#thread.sharedmutex.requirements.general-2.sentence-5)
[3](#thread.sharedmutex.requirements.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7841)
The expression m.lock_shared() is well-formed and has the
following semantics:
[4](#thread.sharedmutex.requirements.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7845)
*Preconditions*: The calling thread has no ownership of the mutex[.](#thread.sharedmutex.requirements.general-4.sentence-1)
[5](#thread.sharedmutex.requirements.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7849)
*Effects*: Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread[.](#thread.sharedmutex.requirements.general-5.sentence-1)
If an exception is thrown then a shared lock has not been acquired for the current thread[.](#thread.sharedmutex.requirements.general-5.sentence-2)
[6](#thread.sharedmutex.requirements.general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7855)
*Synchronization*: Prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#thread.sharedmutex.requirements.general-6.sentence-1)
[7](#thread.sharedmutex.requirements.general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7859)
*Postconditions*: The calling thread has a shared lock on the mutex[.](#thread.sharedmutex.requirements.general-7.sentence-1)
[8](#thread.sharedmutex.requirements.general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7863)
*Return type*: void[.](#thread.sharedmutex.requirements.general-8.sentence-1)
[9](#thread.sharedmutex.requirements.general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7866)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.sharedmutex.requirements.general-9.sentence-1)
[10](#thread.sharedmutex.requirements.general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7870)
*Error conditions*:
- [(10.1)](#thread.sharedmutex.requirements.general-10.1)
operation_not_permitted — if the thread does not have the privilege to perform the operation[.](#thread.sharedmutex.requirements.general-10.1.sentence-1)
- [(10.2)](#thread.sharedmutex.requirements.general-10.2)
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur[.](#thread.sharedmutex.requirements.general-10.2.sentence-1)
[11](#thread.sharedmutex.requirements.general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7878)
The expression m.unlock_shared() is well-formed and has the following semantics:
[12](#thread.sharedmutex.requirements.general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7881)
*Preconditions*: The calling thread holds a shared lock on the mutex[.](#thread.sharedmutex.requirements.general-12.sentence-1)
[13](#thread.sharedmutex.requirements.general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7885)
*Effects*: Releases a shared lock on the mutex held by the calling thread[.](#thread.sharedmutex.requirements.general-13.sentence-1)
[14](#thread.sharedmutex.requirements.general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7889)
*Return type*: void[.](#thread.sharedmutex.requirements.general-14.sentence-1)
[15](#thread.sharedmutex.requirements.general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7892)
*Synchronization*: This operation [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") subsequentlock() operations that obtain ownership on the same object[.](#thread.sharedmutex.requirements.general-15.sentence-1)
[16](#thread.sharedmutex.requirements.general-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7897)
*Throws*: Nothing[.](#thread.sharedmutex.requirements.general-16.sentence-1)
[17](#thread.sharedmutex.requirements.general-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7902)
The expression m.try_lock_shared() is well-formed and has the following semantics:
[18](#thread.sharedmutex.requirements.general-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7905)
*Preconditions*: The calling thread has no ownership of the mutex[.](#thread.sharedmutex.requirements.general-18.sentence-1)
[19](#thread.sharedmutex.requirements.general-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7909)
*Effects*: Attempts to obtain shared ownership of the mutex for the calling
thread without blocking[.](#thread.sharedmutex.requirements.general-19.sentence-1)
If shared ownership is not obtained, there is no
effect and try_lock_shared() immediately returns[.](#thread.sharedmutex.requirements.general-19.sentence-2)
An implementation
may fail to obtain the lock even if it is not held by any other thread[.](#thread.sharedmutex.requirements.general-19.sentence-3)
[20](#thread.sharedmutex.requirements.general-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7916)
*Synchronization*: If try_lock_shared() returns true, prior unlock() operations on the same object synchronize with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this
operation[.](#thread.sharedmutex.requirements.general-20.sentence-1)
[21](#thread.sharedmutex.requirements.general-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7922)
*Return type*: bool[.](#thread.sharedmutex.requirements.general-21.sentence-1)
[22](#thread.sharedmutex.requirements.general-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7925)
*Returns*: true if the shared lock was acquired, otherwise false[.](#thread.sharedmutex.requirements.general-22.sentence-1)
[23](#thread.sharedmutex.requirements.general-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7929)
*Throws*: Nothing[.](#thread.sharedmutex.requirements.general-23.sentence-1)
#### [32.6.4.4.2](#thread.sharedmutex.class) Class shared_mutex [[thread.sharedmutex.class]](thread.sharedmutex.class)
[🔗](#lib:shared_mutex)
namespace std {class shared_mutex {public: shared_mutex(); ~shared_mutex();
shared_mutex(const shared_mutex&) = delete;
shared_mutex& operator=(const shared_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); void unlock_shared(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3Native handles")};}
[1](#thread.sharedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7963)
The class shared_mutex provides a non-recursive mutex
with shared ownership semantics[.](#thread.sharedmutex.class-1.sentence-1)
[2](#thread.sharedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7967)
The class shared_mutex meets
all of the shared mutex requirements ([[thread.sharedmutex.requirements]](#thread.sharedmutex.requirements "32.6.4.4Shared mutex types"))[.](#thread.sharedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.sharedmutex.class-2.sentence-2)
[3](#thread.sharedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7972)
The behavior of a program is undefined if
- [(3.1)](#thread.sharedmutex.class-3.1)
it destroys a shared_mutex object owned by any thread,
- [(3.2)](#thread.sharedmutex.class-3.2)
a thread attempts to recursively gain any ownership of a shared_mutex, or
- [(3.3)](#thread.sharedmutex.class-3.3)
a thread terminates while possessing any ownership of a shared_mutex[.](#thread.sharedmutex.class-3.sentence-1)
[4](#thread.sharedmutex.class-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7980)
shared_mutex may be a synonym for shared_timed_mutex[.](#thread.sharedmutex.class-4.sentence-1)
#### [32.6.4.5](#thread.sharedtimedmutex.requirements) Shared timed mutex types [[thread.sharedtimedmutex.requirements]](thread.sharedtimedmutex.requirements)
#### [32.6.4.5.1](#thread.sharedtimedmutex.requirements.general) General [[thread.sharedtimedmutex.requirements.general]](thread.sharedtimedmutex.requirements.general)
[1](#thread.sharedtimedmutex.requirements.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7987)
The standard library type shared_timed_mutex is a[*shared timed mutex type*](#def:shared_timed_mutex_type "32.6.4.5.1General[thread.sharedtimedmutex.requirements.general]")[.](#thread.sharedtimedmutex.requirements.general-1.sentence-1)
Shared timed mutex types meet the requirements of
timed mutex types ([[thread.timedmutex.requirements]](#thread.timedmutex.requirements "32.6.4.3Timed mutex types")),
shared mutex types ([[thread.sharedmutex.requirements]](#thread.sharedmutex.requirements "32.6.4.4Shared mutex types")), and additionally
meet the requirements set out below[.](#thread.sharedtimedmutex.requirements.general-1.sentence-2)
In this description,m denotes an object of a shared timed mutex type,rel_time denotes an object of an instantiation ofduration ([[time.duration]](time.duration "30.5Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6Class template time_­point[time.point]")[.](#thread.sharedtimedmutex.requirements.general-1.sentence-3)
[*Note [1](#thread.sharedtimedmutex.requirements.general-note-1)*:
The shared timed mutex types meet the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#thread.sharedtimedmutex.requirements.general-1.sentence-4)
— *end note*]
[2](#thread.sharedtimedmutex.requirements.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8003)
The expression m.try_lock_shared_for(rel_time) is well-formed and
has the following semantics:
[3](#thread.sharedtimedmutex.requirements.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8007)
*Preconditions*: The calling thread has no ownership of the mutex[.](#thread.sharedtimedmutex.requirements.general-3.sentence-1)
[4](#thread.sharedtimedmutex.requirements.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8011)
*Effects*: Attempts to obtain
shared lock ownership for the calling thread within the relative
timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications")) specified by rel_time[.](#thread.sharedtimedmutex.requirements.general-4.sentence-1)
If the time
specified by rel_time is less than or equal to rel_time.zero(),
the function attempts to obtain ownership without blocking (as if by callingtry_lock_shared())[.](#thread.sharedtimedmutex.requirements.general-4.sentence-2)
The function returns within the timeout
specified by rel_time only if it has obtained shared ownership of the
mutex object[.](#thread.sharedtimedmutex.requirements.general-4.sentence-3)
[*Note [2](#thread.sharedtimedmutex.requirements.general-note-2)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#thread.sharedtimedmutex.requirements.general-4.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#thread.sharedtimedmutex.requirements.general-4.sentence-5)
[5](#thread.sharedtimedmutex.requirements.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8029)
*Synchronization*: If try_lock_shared_for() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#thread.sharedtimedmutex.requirements.general-5.sentence-1)
[6](#thread.sharedtimedmutex.requirements.general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8035)
*Return type*: bool[.](#thread.sharedtimedmutex.requirements.general-6.sentence-1)
[7](#thread.sharedtimedmutex.requirements.general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8038)
*Returns*: true if the shared lock was acquired, otherwise false[.](#thread.sharedtimedmutex.requirements.general-7.sentence-1)
[8](#thread.sharedtimedmutex.requirements.general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8042)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#thread.sharedtimedmutex.requirements.general-8.sentence-1)
[9](#thread.sharedtimedmutex.requirements.general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8047)
The expression m.try_lock_shared_until(abs_time) is well-formed
and has the following semantics:
[10](#thread.sharedtimedmutex.requirements.general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8051)
*Preconditions*: The calling thread has no ownership of the mutex[.](#thread.sharedtimedmutex.requirements.general-10.sentence-1)
[11](#thread.sharedtimedmutex.requirements.general-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8055)
*Effects*: The function attempts to obtain shared ownership of the mutex[.](#thread.sharedtimedmutex.requirements.general-11.sentence-1)
Ifabs_time has already passed, the function attempts to obtain shared
ownership without blocking (as if by calling try_lock_shared())[.](#thread.sharedtimedmutex.requirements.general-11.sentence-2)
The
function returns before the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))
specified by abs_time only if it has obtained shared ownership of the
mutex object[.](#thread.sharedtimedmutex.requirements.general-11.sentence-3)
[*Note [3](#thread.sharedtimedmutex.requirements.general-note-3)*:
As with try_lock(), there is no guarantee that
ownership will be obtained if the lock is available, but implementations are
expected to make a strong effort to do so[.](#thread.sharedtimedmutex.requirements.general-11.sentence-4)
— *end note*]
If an exception is thrown then a shared lock has not been acquired for
the current thread[.](#thread.sharedtimedmutex.requirements.general-11.sentence-5)
[12](#thread.sharedtimedmutex.requirements.general-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8071)
*Synchronization*: If try_lock_shared_until() returns true, priorunlock() operations on the same object synchronize
with ([[intro.multithread]](intro.multithread "6.10.2Multi-threaded executions and data races")) this operation[.](#thread.sharedtimedmutex.requirements.general-12.sentence-1)
[13](#thread.sharedtimedmutex.requirements.general-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8077)
*Return type*: bool[.](#thread.sharedtimedmutex.requirements.general-13.sentence-1)
[14](#thread.sharedtimedmutex.requirements.general-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8080)
*Returns*: true if the shared lock was acquired, otherwise false[.](#thread.sharedtimedmutex.requirements.general-14.sentence-1)
[15](#thread.sharedtimedmutex.requirements.general-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8084)
*Throws*: Timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4Timing specifications"))[.](#thread.sharedtimedmutex.requirements.general-15.sentence-1)
#### [32.6.4.5.2](#thread.sharedtimedmutex.class) Class shared_timed_mutex [[thread.sharedtimedmutex.class]](thread.sharedtimedmutex.class)
[🔗](#lib:shared_timed_mutex)
namespace std {class shared_timed_mutex {public: shared_timed_mutex(); ~shared_timed_mutex();
shared_timed_mutex(const shared_timed_mutex&) = delete;
shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; // exclusive ownershipvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); template<class Rep, class Period>bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock_shared(); };}
[1](#thread.sharedtimedmutex.class-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8123)
The class shared_timed_mutex provides a non-recursive mutex with shared
ownership semantics[.](#thread.sharedtimedmutex.class-1.sentence-1)
[2](#thread.sharedtimedmutex.class-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8127)
The class shared_timed_mutex meets
all of the shared timed mutex requirements ([[thread.sharedtimedmutex.requirements]](#thread.sharedtimedmutex.requirements "32.6.4.5Shared timed mutex types"))[.](#thread.sharedtimedmutex.class-2.sentence-1)
It is a standard-layout class ([[class.prop]](class.prop "11.2Properties of classes"))[.](#thread.sharedtimedmutex.class-2.sentence-2)
[3](#thread.sharedtimedmutex.class-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8132)
The behavior of a program is undefined if
- [(3.1)](#thread.sharedtimedmutex.class-3.1)
it destroys a shared_timed_mutex object owned by any thread,
- [(3.2)](#thread.sharedtimedmutex.class-3.2)
a thread attempts to recursively gain any ownership of a shared_timed_mutex, or
- [(3.3)](#thread.sharedtimedmutex.class-3.3)
a thread terminates while possessing any ownership of a shared_timed_mutex[.](#thread.sharedtimedmutex.class-3.sentence-1)
### [32.6.5](#thread.lock) Locks [[thread.lock]](thread.lock)
#### [32.6.5.1](#thread.lock.general) General [[thread.lock.general]](thread.lock.general)
[1](#thread.lock.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8144)
A [*lock*](#def:lock) is an object that holds a reference to a lockable object and may unlock the
lockable object during the lock's destruction (such as when leaving block scope)[.](#thread.lock.general-1.sentence-1)
An execution
agent may use a lock to aid in managing ownership of a lockable object in an exception safe
manner[.](#thread.lock.general-1.sentence-2)
A lock is said to [*own*](#def:own) a lockable object if it is currently managing the
ownership of that lockable object for an execution agent[.](#thread.lock.general-1.sentence-3)
A lock does not manage the lifetime
of the lockable object it references[.](#thread.lock.general-1.sentence-4)
[*Note [1](#thread.lock.general-note-1)*:
Locks are intended to ease the burden of
unlocking the lockable object under both normal and exceptional circumstances[.](#thread.lock.general-1.sentence-5)
— *end note*]
[2](#thread.lock.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8156)
Some lock constructors take tag types which describe what should be done with the lockable
object during the lock's construction[.](#thread.lock.general-2.sentence-1)
[🔗](#lib:defer_lock_t)
namespace std {struct defer_lock_t { }; // do not acquire ownership of the mutexstruct try_to_lock_t { }; // try to acquire ownership of the mutex// without blockingstruct adopt_lock_t { }; // assume the calling thread has already// obtained mutex ownership and manage itinline constexpr defer_lock_t defer_lock { }; inline constexpr try_to_lock_t try_to_lock { }; inline constexpr adopt_lock_t adopt_lock { };}
#### [32.6.5.2](#thread.lock.guard) Class template lock_guard [[thread.lock.guard]](thread.lock.guard)
[🔗](#lib:lock_guard)
namespace std {template<class Mutex>class lock_guard {public:using mutex_type = Mutex; explicit lock_guard(mutex_type& m);
lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard();
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete; private: mutex_type& pm; // *exposition only*};}
[1](#thread.lock.guard-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8203)
An object of type lock_guard controls the ownership of a lockable object
within a scope[.](#thread.lock.guard-1.sentence-1)
A lock_guard object maintains ownership of a lockable
object throughout the lock_guard object's [lifetime](basic.life#def:lifetime "6.8.4Lifetime[basic.life]")[.](#thread.lock.guard-1.sentence-2)
The behavior of a program is undefined if the lockable object referenced bypm does not exist for the entire lifetime of the lock_guard object[.](#thread.lock.guard-1.sentence-3)
The supplied Mutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#thread.lock.guard-1.sentence-4)
[🔗](#lib:lock_guard,constructor)
`explicit lock_guard(mutex_type& m);
`
[2](#thread.lock.guard-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8218)
*Effects*: Initializes pm with m[.](#thread.lock.guard-2.sentence-1)
Calls m.lock()[.](#thread.lock.guard-2.sentence-2)
[🔗](#lib:lock_guard,constructor_)
`lock_guard(mutex_type& m, adopt_lock_t);
`
[3](#thread.lock.guard-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8229)
*Preconditions*: The calling thread holds a non-shared lock on m[.](#thread.lock.guard-3.sentence-1)
[4](#thread.lock.guard-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8233)
*Effects*: Initializes pm with m[.](#thread.lock.guard-4.sentence-1)
[5](#thread.lock.guard-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8237)
*Throws*: Nothing[.](#thread.lock.guard-5.sentence-1)
[🔗](#lib:lock_guard,destructor)
`~lock_guard();
`
[6](#thread.lock.guard-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8248)
*Effects*: Equivalent to: pm.unlock()
#### [32.6.5.3](#thread.lock.scoped) Class template scoped_lock [[thread.lock.scoped]](thread.lock.scoped)
[🔗](#lib:scoped_lock)
namespace std {template<class... MutexTypes>class scoped_lock {public:using mutex_type = *see below*; // Only if sizeof...(MutexTypes) == 1 is trueexplicit scoped_lock(MutexTypes&... m); explicit scoped_lock(adopt_lock_t, MutexTypes&... m); ~scoped_lock();
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete; private: tuple<MutexTypes&...> pm; // *exposition only*};}
[1](#thread.lock.scoped-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8276)
An object of type scoped_lock controls the ownership of lockable objects
within a scope[.](#thread.lock.scoped-1.sentence-1)
A scoped_lock object maintains ownership of lockable
objects throughout the scoped_lock object's [lifetime](basic.life#def:lifetime "6.8.4Lifetime[basic.life]")[.](#thread.lock.scoped-1.sentence-2)
The behavior of a program is undefined if the lockable objects referenced bypm do not exist for the entire lifetime of the scoped_lock object[.](#thread.lock.scoped-1.sentence-3)
- [(1.1)](#thread.lock.scoped-1.1)
If sizeof...(MutexTypes) is one,
let Mutex denote the sole type constituting the pack MutexTypes[.](#thread.lock.scoped-1.1.sentence-1)
Mutex shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#thread.lock.scoped-1.1.sentence-2)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") mutex_type denotes the same type as Mutex[.](#thread.lock.scoped-1.1.sentence-3)
- [(1.2)](#thread.lock.scoped-1.2)
Otherwise, all types in the template parameter pack MutexTypes shall meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))
and there is no member mutex_type[.](#thread.lock.scoped-1.2.sentence-1)
[🔗](#lib:scoped_lock,constructor)
`explicit scoped_lock(MutexTypes&... m);
`
[2](#thread.lock.scoped-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8303)
*Effects*: Initializes pm with tie(m...)[.](#thread.lock.scoped-2.sentence-1)
Then if sizeof...(MutexTypes) is 0, no effects[.](#thread.lock.scoped-2.sentence-2)
Otherwise if sizeof...(MutexTypes) is 1, then m.lock()[.](#thread.lock.scoped-2.sentence-3)
Otherwise, lock(m...)[.](#thread.lock.scoped-2.sentence-4)
[🔗](#lib:scoped_lock,constructor_)
`explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
`
[3](#thread.lock.scoped-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8317)
*Preconditions*: The calling thread holds a non-shared lock on each element of m[.](#thread.lock.scoped-3.sentence-1)
[4](#thread.lock.scoped-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8321)
*Effects*: Initializes pm with tie(m...)[.](#thread.lock.scoped-4.sentence-1)
[5](#thread.lock.scoped-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8325)
*Throws*: Nothing[.](#thread.lock.scoped-5.sentence-1)
[🔗](#lib:scoped_lock,destructor)
`~scoped_lock();
`
[6](#thread.lock.scoped-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8336)
*Effects*: For all i in [0, sizeof...(MutexTypes)),get<i>(pm).unlock()[.](#thread.lock.scoped-6.sentence-1)
#### [32.6.5.4](#thread.lock.unique) Class template unique_lock [[thread.lock.unique]](thread.lock.unique)
#### [32.6.5.4.1](#thread.lock.unique.general) General [[thread.lock.unique.general]](thread.lock.unique.general)
[🔗](#lib:unique_lock)
namespace std {template<class Mutex>class unique_lock {public:using mutex_type = Mutex; // [[thread.lock.unique.cons]](#thread.lock.unique.cons "32.6.5.4.2Constructors, destructor, and assignment"), construct/copy/destroy unique_lock() noexcept; explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
unique_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~unique_lock();
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
unique_lock(unique_lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u) noexcept; // [[thread.lock.unique.locking]](#thread.lock.unique.locking "32.6.5.4.3Locking"), lockingvoid lock(); bool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.unique.mod]](#thread.lock.unique.mod "32.6.5.4.4Modifiers"), modifiersvoid swap(unique_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.unique.obs]](#thread.lock.unique.obs "32.6.5.4.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#thread.lock.unique.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8399)
An object of type unique_lock controls the ownership of a lockable
object within a scope[.](#thread.lock.unique.general-1.sentence-1)
Ownership of the lockable object may be acquired at
construction or after construction, and may be transferred, after
acquisition, to another unique_lock object[.](#thread.lock.unique.general-1.sentence-2)
Objects of type unique_lock are not
copyable but are movable[.](#thread.lock.unique.general-1.sentence-3)
The behavior of a program is undefined if the contained pointerpm is not null and the lockable object pointed
to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the unique_lock object[.](#thread.lock.unique.general-1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements ([[thread.req.lockable.basic]](thread.req.lockable.basic "32.2.5.2Cpp17BasicLockable requirements"))[.](#thread.lock.unique.general-1.sentence-5)
[2](#thread.lock.unique.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8411)
[*Note [1](#thread.lock.unique.general-note-1)*:
unique_lock<Mutex> meets the [*Cpp17BasicLockable*](thread.req.lockable.basic#:Cpp17BasicLockable "32.2.5.2Cpp17BasicLockable requirements[thread.req.lockable.basic]") requirements[.](#thread.lock.unique.general-2.sentence-1)
If Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements")),unique_lock<Mutex> also meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements;
if Mutex meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements")),unique_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements[.](#thread.lock.unique.general-2.sentence-2)
— *end note*]
#### [32.6.5.4.2](#thread.lock.unique.cons) Constructors, destructor, and assignment [[thread.lock.unique.cons]](thread.lock.unique.cons)
[🔗](#lib:unique_lock,constructor)
`unique_lock() noexcept;
`
[1](#thread.lock.unique.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8429)
*Postconditions*: pm == nullptr and owns == false[.](#thread.lock.unique.cons-1.sentence-1)
[🔗](#lib:unique_lock,constructor_)
`explicit unique_lock(mutex_type& m);
`
[2](#thread.lock.unique.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8440)
*Effects*: Calls m.lock()[.](#thread.lock.unique.cons-2.sentence-1)
[3](#thread.lock.unique.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8444)
*Postconditions*: pm == addressof(m) and owns == true[.](#thread.lock.unique.cons-3.sentence-1)
[🔗](#lib:unique_lock,constructor__)
`unique_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#thread.lock.unique.cons-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8455)
*Postconditions*: pm == addressof(m) and owns == false[.](#thread.lock.unique.cons-4.sentence-1)
[🔗](#lib:unique_lock,constructor___)
`unique_lock(mutex_type& m, try_to_lock_t);
`
[5](#thread.lock.unique.cons-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8466)
*Preconditions*: The supplied Mutex type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#thread.lock.unique.cons-5.sentence-1)
[6](#thread.lock.unique.cons-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8471)
*Effects*: Calls m.try_lock()[.](#thread.lock.unique.cons-6.sentence-1)
[7](#thread.lock.unique.cons-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8475)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock()[.](#thread.lock.unique.cons-7.sentence-1)
[🔗](#lib:unique_lock,constructor____)
`unique_lock(mutex_type& m, adopt_lock_t);
`
[8](#thread.lock.unique.cons-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8487)
*Preconditions*: The calling thread holds a non-shared lock on m[.](#thread.lock.unique.cons-8.sentence-1)
[9](#thread.lock.unique.cons-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8491)
*Postconditions*: pm == addressof(m) and owns == true[.](#thread.lock.unique.cons-9.sentence-1)
[10](#thread.lock.unique.cons-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8495)
*Throws*: Nothing[.](#thread.lock.unique.cons-10.sentence-1)
[🔗](#lib:unique_lock,constructor_____)
`template<class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#thread.lock.unique.cons-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8507)
*Preconditions*: The supplied Mutex type meets the[*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.lock.unique.cons-11.sentence-1)
[12](#thread.lock.unique.cons-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8512)
*Effects*: Calls m.try_lock_until(abs_time)[.](#thread.lock.unique.cons-12.sentence-1)
[13](#thread.lock.unique.cons-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8516)
*Postconditions*: pm == addressof(m) and owns == res,
where res is
the value returned by the call to m.try_lock_until(abs_time)[.](#thread.lock.unique.cons-13.sentence-1)
[🔗](#lib:unique_lock,constructor______)
`template<class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
`
[14](#thread.lock.unique.cons-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8530)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.lock.unique.cons-14.sentence-1)
[15](#thread.lock.unique.cons-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8534)
*Effects*: Calls m.try_lock_for(rel_time)[.](#thread.lock.unique.cons-15.sentence-1)
[16](#thread.lock.unique.cons-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8538)
*Postconditions*: pm == addressof(m) and owns == res,
where res is the value returned by the call to m.try_lock_for(rel_time)[.](#thread.lock.unique.cons-16.sentence-1)
[🔗](#lib:unique_lock,constructor_______)
`unique_lock(unique_lock&& u) noexcept;
`
[17](#thread.lock.unique.cons-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8550)
*Postconditions*: pm == u_p.pm and owns == u_p.owns (where u_p is the state of u just prior to this construction), u.pm == 0 and u.owns == false[.](#thread.lock.unique.cons-17.sentence-1)
[🔗](#lib:operator=,unique_lock)
`unique_lock& operator=(unique_lock&& u) noexcept;
`
[18](#thread.lock.unique.cons-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8561)
*Effects*: Equivalent to: unique_lock(std::move(u)).swap(*this)
[19](#thread.lock.unique.cons-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8565)
*Returns*: *this[.](#thread.lock.unique.cons-19.sentence-1)
[🔗](#lib:unique_lock,destructor)
`~unique_lock();
`
[20](#thread.lock.unique.cons-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8576)
*Effects*: If owns calls pm->unlock()[.](#thread.lock.unique.cons-20.sentence-1)
#### [32.6.5.4.3](#thread.lock.unique.locking) Locking [[thread.lock.unique.locking]](thread.lock.unique.locking)
[🔗](#lib:lock,unique_lock)
`void lock();
`
[1](#thread.lock.unique.locking-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8589)
*Effects*: As if by pm->lock()[.](#thread.lock.unique.locking-1.sentence-1)
[2](#thread.lock.unique.locking-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8593)
*Postconditions*: owns == true[.](#thread.lock.unique.locking-2.sentence-1)
[3](#thread.lock.unique.locking-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8597)
*Throws*: Any exception thrown by pm->lock()[.](#thread.lock.unique.locking-3.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.unique.locking-3.sentence-2)
[4](#thread.lock.unique.locking-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8602)
*Error conditions*:
- [(4.1)](#thread.lock.unique.locking-4.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.unique.locking-4.1.sentence-1)
- [(4.2)](#thread.lock.unique.locking-4.2)
resource_deadlock_would_occur — if on entry owns is true[.](#thread.lock.unique.locking-4.2.sentence-1)
[🔗](#lib:try_lock,unique_lock)
`bool try_lock();
`
[5](#thread.lock.unique.locking-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8617)
*Preconditions*: The supplied Mutex meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#thread.lock.unique.locking-5.sentence-1)
[6](#thread.lock.unique.locking-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8622)
*Effects*: As if by pm->try_lock()[.](#thread.lock.unique.locking-6.sentence-1)
[7](#thread.lock.unique.locking-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8626)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock()[.](#thread.lock.unique.locking-7.sentence-1)
[8](#thread.lock.unique.locking-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8631)
*Returns*: The value returned by pm->try_lock()[.](#thread.lock.unique.locking-8.sentence-1)
[9](#thread.lock.unique.locking-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8635)
*Throws*: Any exception thrown by pm->try_lock()[.](#thread.lock.unique.locking-9.sentence-1)
system_error when an exception
is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.unique.locking-9.sentence-2)
[10](#thread.lock.unique.locking-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8640)
*Error conditions*:
- [(10.1)](#thread.lock.unique.locking-10.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.unique.locking-10.1.sentence-1)
- [(10.2)](#thread.lock.unique.locking-10.2)
resource_deadlock_would_occur — if on entry owns is true[.](#thread.lock.unique.locking-10.2.sentence-1)
[🔗](#lib:try_lock_until,unique_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[11](#thread.lock.unique.locking-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8656)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.lock.unique.locking-11.sentence-1)
[12](#thread.lock.unique.locking-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8661)
*Effects*: As if by pm->try_lock_until(abs_time)[.](#thread.lock.unique.locking-12.sentence-1)
[13](#thread.lock.unique.locking-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8665)
*Postconditions*: owns == res, where res is the value returned bypm->try_lock_until(abs_time)[.](#thread.lock.unique.locking-13.sentence-1)
[14](#thread.lock.unique.locking-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8670)
*Returns*: The value returned by pm->try_lock_until(abs_time)[.](#thread.lock.unique.locking-14.sentence-1)
[15](#thread.lock.unique.locking-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8674)
*Throws*: Any exception thrown by pm->try_lock_until(abstime)[.](#thread.lock.unique.locking-15.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.unique.locking-15.sentence-2)
[16](#thread.lock.unique.locking-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8679)
*Error conditions*:
- [(16.1)](#thread.lock.unique.locking-16.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.unique.locking-16.1.sentence-1)
- [(16.2)](#thread.lock.unique.locking-16.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.unique.locking-16.2.sentence-1)
[🔗](#lib:try_lock_for,unique_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[17](#thread.lock.unique.locking-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8695)
*Preconditions*: The supplied Mutex type meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.lock.unique.locking-17.sentence-1)
[18](#thread.lock.unique.locking-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8699)
*Effects*: As if by pm->try_lock_for(rel_time)[.](#thread.lock.unique.locking-18.sentence-1)
[19](#thread.lock.unique.locking-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8703)
*Postconditions*: owns == res, where res is the value returned by pm->try_lock_for(rel_time)[.](#thread.lock.unique.locking-19.sentence-1)
[20](#thread.lock.unique.locking-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8707)
*Returns*: The value returned by pm->try_lock_for(rel_time)[.](#thread.lock.unique.locking-20.sentence-1)
[21](#thread.lock.unique.locking-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8711)
*Throws*: Any exception thrown by pm->try_lock_for(rel_time)[.](#thread.lock.unique.locking-21.sentence-1)
system_error when an
exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.unique.locking-21.sentence-2)
[22](#thread.lock.unique.locking-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8716)
*Error conditions*:
- [(22.1)](#thread.lock.unique.locking-22.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.unique.locking-22.1.sentence-1)
- [(22.2)](#thread.lock.unique.locking-22.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.unique.locking-22.2.sentence-1)
[🔗](#lib:unlock,unique_lock)
`void unlock();
`
[23](#thread.lock.unique.locking-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8731)
*Effects*: As if by pm->unlock()[.](#thread.lock.unique.locking-23.sentence-1)
[24](#thread.lock.unique.locking-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8735)
*Postconditions*: owns == false[.](#thread.lock.unique.locking-24.sentence-1)
[25](#thread.lock.unique.locking-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8739)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.unique.locking-25.sentence-1)
[26](#thread.lock.unique.locking-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8744)
*Error conditions*:
- [(26.1)](#thread.lock.unique.locking-26.1)
operation_not_permitted — if on entry owns is false[.](#thread.lock.unique.locking-26.sentence-1)
#### [32.6.5.4.4](#thread.lock.unique.mod) Modifiers [[thread.lock.unique.mod]](thread.lock.unique.mod)
[🔗](#lib:swap,unique_lock)
`void swap(unique_lock& u) noexcept;
`
[1](#thread.lock.unique.mod-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8759)
*Effects*: Swaps the data members of *this and u[.](#thread.lock.unique.mod-1.sentence-1)
[🔗](#lib:release,unique_lock)
`mutex_type* release() noexcept;
`
[2](#thread.lock.unique.mod-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8770)
*Postconditions*: pm == 0 and owns == false[.](#thread.lock.unique.mod-2.sentence-1)
[3](#thread.lock.unique.mod-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8774)
*Returns*: The previous value of pm[.](#thread.lock.unique.mod-3.sentence-1)
[🔗](#lib:swap,unique_lock_)
`template<class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
`
[4](#thread.lock.unique.mod-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8786)
*Effects*: As if by x.swap(y)[.](#thread.lock.unique.mod-4.sentence-1)
#### [32.6.5.4.5](#thread.lock.unique.obs) Observers [[thread.lock.unique.obs]](thread.lock.unique.obs)
[🔗](#lib:owns_lock,unique_lock)
`bool owns_lock() const noexcept;
`
[1](#thread.lock.unique.obs-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8799)
*Returns*: owns[.](#thread.lock.unique.obs-1.sentence-1)
[🔗](#lib:operator_bool,unique_lock)
`explicit operator bool() const noexcept;
`
[2](#thread.lock.unique.obs-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8810)
*Returns*: owns[.](#thread.lock.unique.obs-2.sentence-1)
[🔗](#lib:mutex,unique_lock)
`mutex_type *mutex() const noexcept;
`
[3](#thread.lock.unique.obs-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8821)
*Returns*: pm[.](#thread.lock.unique.obs-3.sentence-1)
#### [32.6.5.5](#thread.lock.shared) Class template shared_lock [[thread.lock.shared]](thread.lock.shared)
#### [32.6.5.5.1](#thread.lock.shared.general) General [[thread.lock.shared.general]](thread.lock.shared.general)
[🔗](#lib:shared_lock)
namespace std {template<class Mutex>class shared_lock {public:using mutex_type = Mutex; // [[thread.lock.shared.cons]](#thread.lock.shared.cons "32.6.5.5.2Constructors, destructor, and assignment"), construct/copy/destroy shared_lock() noexcept; explicit shared_lock(mutex_type& m); // blocking shared_lock(mutex_type& m, defer_lock_t) noexcept;
shared_lock(mutex_type& m, try_to_lock_t);
shared_lock(mutex_type& m, adopt_lock_t); template<class Clock, class Duration> shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time); ~shared_lock();
shared_lock(const shared_lock&) = delete;
shared_lock& operator=(const shared_lock&) = delete;
shared_lock(shared_lock&& u) noexcept;
shared_lock& operator=(shared_lock&& u) noexcept; // [[thread.lock.shared.locking]](#thread.lock.shared.locking "32.6.5.5.3Locking"), lockingvoid lock(); // blockingbool try_lock(); template<class Rep, class Period>bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration>bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [[thread.lock.shared.mod]](#thread.lock.shared.mod "32.6.5.5.4Modifiers"), modifiersvoid swap(shared_lock& u) noexcept;
mutex_type* release() noexcept; // [[thread.lock.shared.obs]](#thread.lock.shared.obs "32.6.5.5.5Observers"), observersbool owns_lock() const noexcept; explicit operator bool() const noexcept;
mutex_type* mutex() const noexcept; private: mutex_type* pm; // *exposition only*bool owns; // *exposition only*};}
[1](#thread.lock.shared.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8881)
An object of type shared_lock controls the shared ownership of a
lockable object within a scope[.](#thread.lock.shared.general-1.sentence-1)
Shared ownership of the lockable object may be
acquired at construction or after construction, and may be transferred, after
acquisition, to another shared_lock object[.](#thread.lock.shared.general-1.sentence-2)
Objects of typeshared_lock are not copyable but are movable[.](#thread.lock.shared.general-1.sentence-3)
The behavior of a program
is undefined if the contained pointer pm is not null and the lockable
object pointed to by pm does not exist for the entire remaining
lifetime ([[basic.life]](basic.life "6.8.4Lifetime")) of the shared_lock object[.](#thread.lock.shared.general-1.sentence-4)
The suppliedMutex type shall meet the [*Cpp17SharedLockable*](thread.req.lockable.shared#:Cpp17SharedLockable "32.2.5.5Cpp17SharedLockable requirements[thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5Cpp17SharedLockable requirements"))[.](#thread.lock.shared.general-1.sentence-5)
[2](#thread.lock.shared.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8893)
[*Note [1](#thread.lock.shared.general-note-1)*:
shared_lock<Mutex> meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements"))[.](#thread.lock.shared.general-2.sentence-1)
If Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements")),shared_lock<Mutex> also meets the [*Cpp17TimedLockable*](thread.req.lockable.timed#:Cpp17TimedLockable "32.2.5.4Cpp17TimedLockable requirements[thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4Cpp17TimedLockable requirements"))[.](#thread.lock.shared.general-2.sentence-2)
— *end note*]
#### [32.6.5.5.2](#thread.lock.shared.cons) Constructors, destructor, and assignment [[thread.lock.shared.cons]](thread.lock.shared.cons)
[🔗](#lib:shared_lock,constructor)
`shared_lock() noexcept;
`
[1](#thread.lock.shared.cons-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8911)
*Postconditions*: pm == nullptr and owns == false[.](#thread.lock.shared.cons-1.sentence-1)
[🔗](#lib:shared_lock,constructor_)
`explicit shared_lock(mutex_type& m);
`
[2](#thread.lock.shared.cons-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8922)
*Effects*: Calls m.lock_shared()[.](#thread.lock.shared.cons-2.sentence-1)
[3](#thread.lock.shared.cons-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8926)
*Postconditions*: pm == addressof(m) and owns == true[.](#thread.lock.shared.cons-3.sentence-1)
[🔗](#lib:shared_lock,constructor__)
`shared_lock(mutex_type& m, defer_lock_t) noexcept;
`
[4](#thread.lock.shared.cons-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8937)
*Postconditions*: pm == addressof(m) and owns == false[.](#thread.lock.shared.cons-4.sentence-1)
[🔗](#lib:shared_lock,constructor___)
`shared_lock(mutex_type& m, try_to_lock_t);
`
[5](#thread.lock.shared.cons-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8948)
*Effects*: Calls m.try_lock_shared()[.](#thread.lock.shared.cons-5.sentence-1)
[6](#thread.lock.shared.cons-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8952)
*Postconditions*: pm == addressof(m) and owns == res where res is the
value returned by the call to m.try_lock_shared()[.](#thread.lock.shared.cons-6.sentence-1)
[🔗](#lib:shared_lock,constructor____)
`shared_lock(mutex_type& m, adopt_lock_t);
`
[7](#thread.lock.shared.cons-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8965)
*Preconditions*: The calling thread holds a shared lock on m[.](#thread.lock.shared.cons-7.sentence-1)
[8](#thread.lock.shared.cons-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8969)
*Postconditions*: pm == addressof(m) and owns == true[.](#thread.lock.shared.cons-8.sentence-1)
[🔗](#lib:shared_lock,constructor_____)
`template<class Clock, class Duration>
shared_lock(mutex_type& m,
const chrono::time_point<Clock, Duration>& abs_time);
`
[9](#thread.lock.shared.cons-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8982)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#thread.lock.shared.cons-9.sentence-1)
[10](#thread.lock.shared.cons-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8987)
*Effects*: Calls m.try_lock_shared_until(abs_time)[.](#thread.lock.shared.cons-10.sentence-1)
[11](#thread.lock.shared.cons-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L8991)
*Postconditions*: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_lock_shared_until(abs_time)[.](#thread.lock.shared.cons-11.sentence-1)
[🔗](#lib:shared_lock,constructor______)
`template<class Rep, class Period>
shared_lock(mutex_type& m,
const chrono::duration<Rep, Period>& rel_time);
`
[12](#thread.lock.shared.cons-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9006)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#thread.lock.shared.cons-12.sentence-1)
[13](#thread.lock.shared.cons-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9011)
*Effects*: Calls m.try_lock_shared_for(rel_time)[.](#thread.lock.shared.cons-13.sentence-1)
[14](#thread.lock.shared.cons-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9015)
*Postconditions*: pm == addressof(m) and owns == res where res is
the value returned by the call to m.try_lock_shared_for(rel_time)[.](#thread.lock.shared.cons-14.sentence-1)
[🔗](#lib:shared_lock,destructor)
`~shared_lock();
`
[15](#thread.lock.shared.cons-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9028)
*Effects*: If owns calls pm->unlock_shared()[.](#thread.lock.shared.cons-15.sentence-1)
[🔗](#lib:shared_lock,constructor_______)
`shared_lock(shared_lock&& sl) noexcept;
`
[16](#thread.lock.shared.cons-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9039)
*Postconditions*: pm == sl_p.pm and owns == sl_p.owns (wheresl_p is the state of sl just prior to this construction),sl.pm == nullptr and sl.owns == false[.](#thread.lock.shared.cons-16.sentence-1)
[🔗](#lib:operator=,shared_lock)
`shared_lock& operator=(shared_lock&& sl) noexcept;
`
[17](#thread.lock.shared.cons-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9052)
*Effects*: Equivalent to: shared_lock(std::move(sl)).swap(*this)
[18](#thread.lock.shared.cons-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9056)
*Returns*: *this[.](#thread.lock.shared.cons-18.sentence-1)
#### [32.6.5.5.3](#thread.lock.shared.locking) Locking [[thread.lock.shared.locking]](thread.lock.shared.locking)
[🔗](#lib:lock,shared_lock)
`void lock();
`
[1](#thread.lock.shared.locking-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9069)
*Effects*: As if by pm->lock_shared()[.](#thread.lock.shared.locking-1.sentence-1)
[2](#thread.lock.shared.locking-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9073)
*Postconditions*: owns == true[.](#thread.lock.shared.locking-2.sentence-1)
[3](#thread.lock.shared.locking-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9077)
*Throws*: Any exception thrown by pm->lock_shared()[.](#thread.lock.shared.locking-3.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.shared.locking-3.sentence-2)
[4](#thread.lock.shared.locking-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9082)
*Error conditions*:
- [(4.1)](#thread.lock.shared.locking-4.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.shared.locking-4.1.sentence-1)
- [(4.2)](#thread.lock.shared.locking-4.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.shared.locking-4.2.sentence-1)
[🔗](#lib:try_lock,shared_lock)
`bool try_lock();
`
[5](#thread.lock.shared.locking-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9097)
*Effects*: As if by pm->try_lock_shared()[.](#thread.lock.shared.locking-5.sentence-1)
[6](#thread.lock.shared.locking-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9101)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared()[.](#thread.lock.shared.locking-6.sentence-1)
[7](#thread.lock.shared.locking-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9106)
*Returns*: The value returned by the call to pm->try_lock_shared()[.](#thread.lock.shared.locking-7.sentence-1)
[8](#thread.lock.shared.locking-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9110)
*Throws*: Any exception thrown by pm->try_lock_shared()[.](#thread.lock.shared.locking-8.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.shared.locking-8.sentence-2)
[9](#thread.lock.shared.locking-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9115)
*Error conditions*:
- [(9.1)](#thread.lock.shared.locking-9.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.shared.locking-9.1.sentence-1)
- [(9.2)](#thread.lock.shared.locking-9.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.shared.locking-9.2.sentence-1)
[🔗](#lib:try_lock_until,shared_lock)
`template<class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
`
[10](#thread.lock.shared.locking-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9131)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#thread.lock.shared.locking-10.sentence-1)
[11](#thread.lock.shared.locking-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9136)
*Effects*: As if by pm->try_lock_shared_until(abs_time)[.](#thread.lock.shared.locking-11.sentence-1)
[12](#thread.lock.shared.locking-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9140)
*Postconditions*: owns == res, where res is the value returned by
the call to pm->try_lock_shared_until(abs_time)[.](#thread.lock.shared.locking-12.sentence-1)
[13](#thread.lock.shared.locking-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9145)
*Returns*: The value returned by the call topm->try_lock_shared_until(abs_time)[.](#thread.lock.shared.locking-13.sentence-1)
[14](#thread.lock.shared.locking-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9150)
*Throws*: Any exception thrown by pm->try_lock_shared_until(abs_time)[.](#thread.lock.shared.locking-14.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.shared.locking-14.sentence-2)
[15](#thread.lock.shared.locking-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9155)
*Error conditions*:
- [(15.1)](#thread.lock.shared.locking-15.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.shared.locking-15.1.sentence-1)
- [(15.2)](#thread.lock.shared.locking-15.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.shared.locking-15.2.sentence-1)
[🔗](#lib:try_lock_for,shared_lock)
`template<class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
`
[16](#thread.lock.shared.locking-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9171)
*Preconditions*: Mutex meets the [*Cpp17SharedTimedLockable*](thread.req.lockable.shared.timed#:Cpp17SharedTimedLockable "32.2.5.6Cpp17SharedTimedLockable requirements[thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6Cpp17SharedTimedLockable requirements"))[.](#thread.lock.shared.locking-16.sentence-1)
[17](#thread.lock.shared.locking-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9176)
*Effects*: As if by pm->try_lock_shared_for(rel_time)[.](#thread.lock.shared.locking-17.sentence-1)
[18](#thread.lock.shared.locking-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9180)
*Postconditions*: owns == res, where res is the value returned by the call to pm->try_lock_shared_for(rel_time)[.](#thread.lock.shared.locking-18.sentence-1)
[19](#thread.lock.shared.locking-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9184)
*Returns*: The value returned by the call to pm->try_lock_shared_for(rel_time)[.](#thread.lock.shared.locking-19.sentence-1)
[20](#thread.lock.shared.locking-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9188)
*Throws*: Any exception thrown by pm->try_lock_shared_for(rel_time)[.](#thread.lock.shared.locking-20.sentence-1)
system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.shared.locking-20.sentence-2)
[21](#thread.lock.shared.locking-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9192)
*Error conditions*:
- [(21.1)](#thread.lock.shared.locking-21.1)
operation_not_permitted — if pm is nullptr[.](#thread.lock.shared.locking-21.1.sentence-1)
- [(21.2)](#thread.lock.shared.locking-21.2)
resource_deadlock_would_occur — if on entry owns istrue[.](#thread.lock.shared.locking-21.2.sentence-1)
[🔗](#lib:unlock,shared_lock)
`void unlock();
`
[22](#thread.lock.shared.locking-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9207)
*Effects*: As if by pm->unlock_shared()[.](#thread.lock.shared.locking-22.sentence-1)
[23](#thread.lock.shared.locking-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9211)
*Postconditions*: owns == false[.](#thread.lock.shared.locking-23.sentence-1)
[24](#thread.lock.shared.locking-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9215)
*Throws*: system_error when an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions"))[.](#thread.lock.shared.locking-24.sentence-1)
[25](#thread.lock.shared.locking-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9219)
*Error conditions*:
- [(25.1)](#thread.lock.shared.locking-25.1)
operation_not_permitted — if on entry owns isfalse[.](#thread.lock.shared.locking-25.sentence-1)
#### [32.6.5.5.4](#thread.lock.shared.mod) Modifiers [[thread.lock.shared.mod]](thread.lock.shared.mod)
[🔗](#lib:swap,shared_lock)
`void swap(shared_lock& sl) noexcept;
`
[1](#thread.lock.shared.mod-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9235)
*Effects*: Swaps the data members of *this and sl[.](#thread.lock.shared.mod-1.sentence-1)
[🔗](#lib:release,shared_lock)
`mutex_type* release() noexcept;
`
[2](#thread.lock.shared.mod-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9246)
*Postconditions*: pm == nullptr and owns == false[.](#thread.lock.shared.mod-2.sentence-1)
[3](#thread.lock.shared.mod-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9250)
*Returns*: The previous value of pm[.](#thread.lock.shared.mod-3.sentence-1)
[🔗](#lib:swap,shared_lock_)
`template<class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
`
[4](#thread.lock.shared.mod-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9262)
*Effects*: As if by x.swap(y)[.](#thread.lock.shared.mod-4.sentence-1)
#### [32.6.5.5.5](#thread.lock.shared.obs) Observers [[thread.lock.shared.obs]](thread.lock.shared.obs)
[🔗](#lib:owns_lock,shared_lock)
`bool owns_lock() const noexcept;
`
[1](#thread.lock.shared.obs-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9275)
*Returns*: owns[.](#thread.lock.shared.obs-1.sentence-1)
[🔗](#lib:operator_bool,shared_lock)
`explicit operator bool() const noexcept;
`
[2](#thread.lock.shared.obs-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9286)
*Returns*: owns[.](#thread.lock.shared.obs-2.sentence-1)
[🔗](#lib:mutex,shared_lock)
`mutex_type* mutex() const noexcept;
`
[3](#thread.lock.shared.obs-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9297)
*Returns*: pm[.](#thread.lock.shared.obs-3.sentence-1)
### [32.6.6](#thread.lock.algorithm) Generic locking algorithms [[thread.lock.algorithm]](thread.lock.algorithm)
[🔗](#lib:try_lock)
`template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
`
[1](#thread.lock.algorithm-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9310)
*Preconditions*: Each template parameter type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements[.](#thread.lock.algorithm-1.sentence-1)
[*Note [1](#thread.lock.algorithm-note-1)*:
Theunique_lock class template meets these requirements when suitably instantiated[.](#thread.lock.algorithm-1.sentence-2)
— *end note*]
[2](#thread.lock.algorithm-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9318)
*Effects*: Calls try_lock() for each argument in order beginning with the
first until all arguments have been processed or a call to try_lock() fails,
either by returning false or by throwing an exception[.](#thread.lock.algorithm-2.sentence-1)
If a call totry_lock() fails, unlock() is called for all prior arguments
with no further calls to try_lock()[.](#thread.lock.algorithm-2.sentence-2)
[3](#thread.lock.algorithm-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9326)
*Returns*: -1 if all calls to try_lock() returned true,
otherwise a zero-based index value that indicates the argument for which try_lock() returned false[.](#thread.lock.algorithm-3.sentence-1)
[🔗](#lib:lock)
`template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
`
[4](#thread.lock.algorithm-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9339)
*Preconditions*: Each template parameter type meets the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") requirements[.](#thread.lock.algorithm-4.sentence-1)
[*Note [2](#thread.lock.algorithm-note-2)*:
Theunique_lock class template meets these requirements when suitably instantiated[.](#thread.lock.algorithm-4.sentence-2)
— *end note*]
[5](#thread.lock.algorithm-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9347)
*Effects*: All arguments are locked via a sequence of calls to lock(),try_lock(), or unlock() on each argument[.](#thread.lock.algorithm-5.sentence-1)
The sequence of calls does
not result in deadlock, but is otherwise unspecified[.](#thread.lock.algorithm-5.sentence-2)
[*Note [3](#thread.lock.algorithm-note-3)*:
A deadlock avoidance
algorithm such as try-and-back-off can be used, but the specific algorithm is not
specified to avoid over-constraining implementations[.](#thread.lock.algorithm-5.sentence-3)
— *end note*]
If a call tolock() or try_lock() throws an exception, unlock() is
called for any argument that had been locked by a call to lock() ortry_lock()[.](#thread.lock.algorithm-5.sentence-4)
### [32.6.7](#thread.once) Call once [[thread.once]](thread.once)
#### [32.6.7.1](#thread.once.onceflag) Struct once_flag [[thread.once.onceflag]](thread.once.onceflag)
[🔗](#lib:once_flag)
namespace std {struct once_flag {constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete; };}
[1](#thread.once.onceflag-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9379)
The class once_flag is an opaque data structure that call_once uses to
initialize data without causing a data race or deadlock[.](#thread.once.onceflag-1.sentence-1)
[🔗](#lib:once_flag_)
`constexpr once_flag() noexcept;
`
[2](#thread.once.onceflag-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9389)
*Synchronization*: The construction of a once_flag object is not synchronized[.](#thread.once.onceflag-2.sentence-1)
[3](#thread.once.onceflag-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9393)
*Postconditions*: The object's internal state is set to indicate to an invocation ofcall_once with the object as its initial argument that no function has been
called[.](#thread.once.onceflag-3.sentence-1)
#### [32.6.7.2](#thread.once.callonce) Function call_once [[thread.once.callonce]](thread.once.callonce)
[🔗](#lib:call_once)
`template<class Callable, class... Args>
void call_once(once_flag& flag, Callable&& func, Args&&... args);
`
[1](#thread.once.callonce-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9409)
*Mandates*: is_invocable_v<Callable, Args...> is true[.](#thread.once.callonce-1.sentence-1)
[2](#thread.once.callonce-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9413)
*Effects*: An execution of call_once that does not call its func is a[*passive*](#def:passive) execution[.](#thread.once.callonce-2.sentence-1)
An execution of call_once that calls its func is an [*active*](#def:active) execution[.](#thread.once.callonce-2.sentence-2)
An active execution evaluates*INVOKE*(std::forward<Callable>(func),
std::forward<Args>(args)...) ([[func.require]](func.require "22.10.4Requirements"))[.](#thread.once.callonce-2.sentence-3)
If such a call to func throws an exception the execution is [*exceptional*](#def:exceptional), otherwise it is [*returning*](#def:returning)[.](#thread.once.callonce-2.sentence-4)
An exceptional execution propagates the exception to the caller ofcall_once[.](#thread.once.callonce-2.sentence-5)
Among all executions of call_once for any givenonce_flag: at most one is a returning execution; if there is a
returning execution, it is the last active execution; and there are
passive executions only if there is a returning execution[.](#thread.once.callonce-2.sentence-6)
[*Note [1](#thread.once.callonce-note-1)*:
Passive
executions allow other threads to reliably observe the results produced by the
earlier returning execution[.](#thread.once.callonce-2.sentence-7)
— *end note*]
[3](#thread.once.callonce-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9433)
*Synchronization*: For any given once_flag: all active executions occur in a total
order; completion of an active execution [synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-threaded executions and data races[intro.multithread]") the start of the next one in this total order; and the returning execution
synchronizes with the return from all passive executions[.](#thread.once.callonce-3.sentence-1)
[4](#thread.once.callonce-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9440)
*Throws*: system_error when
an exception is required ([[thread.req.exception]](thread.req.exception "32.2.2Exceptions")), or any exception thrown by func[.](#thread.once.callonce-4.sentence-1)
[5](#thread.once.callonce-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L9445)
[*Example [1](#thread.once.callonce-example-1)*: // global flag, regular functionvoid init();
std::once_flag flag;
void f() { std::call_once(flag, init);}// function static flag, function objectstruct initializer {void operator()();};
void g() {static std::once_flag flag2;
std::call_once(flag2, initializer());}// object flag, member functionclass information { std::once_flag verified; void verifier();public:void verify() { std::call_once(verified, &information::verifier, *this); }}; — *end example*]