[thread.mutex.requirements] # 32 Concurrency support library [[thread]](./#thread) ## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#requirements) ### 32.6.4 Mutex requirements [thread.mutex.requirements] #### [32.6.4.1](#general) General [[thread.mutex.requirements.general]](thread.mutex.requirements.general) [1](#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.5 Requirements for Cpp17Lockable types [thread.req.lockable]")[.](#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[.](#general-1.sentence-2) Mutexes can be either recursive or non-recursive, and can grant simultaneous ownership to one or many execution agents[.](#general-1.sentence-3) Both recursive and non-recursive mutexes are supplied[.](#general-1.sentence-4) #### [32.6.4.2](#mutex) Mutex types [[thread.mutex.requirements.mutex]](thread.mutex.requirements.mutex) #### [32.6.4.2.1](#mutex.general) General [[thread.mutex.requirements.mutex.general]](thread.mutex.requirements.mutex.general) [1](#mutex.general-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7330) The [*mutex types*](#def:mutex_types "32.6.4.2.1 General [thread.mutex.requirements.mutex.general]") are the standard library types mutex,recursive_mutex, timed_mutex, recursive_timed_mutex,shared_mutex, and shared_timed_mutex[.](#mutex.general-1.sentence-1) They meet the requirements set out in [[thread.mutex.requirements.mutex]](#mutex "32.6.4.2 Mutex types")[.](#mutex.general-1.sentence-2) In this description, m denotes an object of a mutex type[.](#mutex.general-1.sentence-3) [*Note [1](#mutex.general-note-1)*: The mutex types meet the [*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3 Cpp17Lockable requirements"))[.](#mutex.general-1.sentence-4) — *end note*] [2](#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.2 Template argument requirements [utility.arg.requirements]") and [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template argument requirements [utility.arg.requirements]")[.](#mutex.general-2.sentence-1) If initialization of an object of a mutex type fails, an exception of type system_error is thrown[.](#mutex.general-2.sentence-2) The mutex types are neither copyable nor movable[.](#mutex.general-2.sentence-3) [3](#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)](#mutex.general-3.1) resource_unavailable_try_again — if any native handle type manipulated is not available[.](#mutex.general-3.1.sentence-1) - [(3.2)](#mutex.general-3.2) operation_not_permitted — if the thread does not have the privilege to perform the operation[.](#mutex.general-3.2.sentence-1) - [(3.3)](#mutex.general-3.3) invalid_argument — if any native handle type manipulated as part of mutex construction is incorrect[.](#mutex.general-3.3.sentence-1) [4](#mutex.general-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7357) The implementation provides lock and unlock operations, as described below[.](#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.2 Multi-threaded executions and data races"))[.](#mutex.general-4.sentence-2) The lock and unlock operations on a single mutex appears to occur in a single total order[.](#mutex.general-4.sentence-3) [*Note [2](#mutex.general-note-2)*: This can be viewed as the [modification order](intro.multithread#def:modification_order "6.10.2 Multi-threaded executions and data races [intro.multithread]") of the mutex[.](#mutex.general-4.sentence-4) — *end note*] [*Note [3](#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[.](#mutex.general-4.sentence-5) — *end note*] [5](#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](#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[.](#mutex.general-6.sentence-1) [7](#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[.](#mutex.general-7.sentence-1) [8](#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.2 Multi-threaded executions and data races")) this operation[.](#mutex.general-8.sentence-1) [9](#mutex.general-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7393) *Postconditions*: The calling thread owns the mutex[.](#mutex.general-9.sentence-1) [10](#mutex.general-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7397) *Return type*: void[.](#mutex.general-10.sentence-1) [11](#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.2 Exceptions"))[.](#mutex.general-11.sentence-1) [12](#mutex.general-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7405) *Error conditions*: - [(12.1)](#mutex.general-12.1) operation_not_permitted — if the thread does not have the privilege to perform the operation[.](#mutex.general-12.1.sentence-1) - [(12.2)](#mutex.general-12.2) resource_deadlock_would_occur — if the implementation detects that a deadlock would occur[.](#mutex.general-12.2.sentence-1) [13](#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](#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[.](#mutex.general-14.sentence-1) [15](#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[.](#mutex.general-15.sentence-1) If ownership is not obtained, there is no effect and try_lock() immediately returns[.](#mutex.general-15.sentence-2) An implementation may fail to obtain the lock even if it is not held by any other thread[.](#mutex.general-15.sentence-3) [*Note [4](#mutex.general-note-4)*: This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange ([[atomics]](atomics "32.5 Atomic operations"))[.](#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[.](#mutex.general-15.sentence-5) [16](#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.2 Multi-threaded executions and data races [intro.multithread]") this operation[.](#mutex.general-16.sentence-1) [*Note [5](#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[.](#mutex.general-16.sentence-2) — *end note*] [17](#mutex.general-17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7449) *Return type*: bool[.](#mutex.general-17.sentence-1) [18](#mutex.general-18) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7452) *Returns*: true if ownership was obtained, otherwise false[.](#mutex.general-18.sentence-1) [19](#mutex.general-19) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7456) *Throws*: Nothing[.](#mutex.general-19.sentence-1) [20](#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](#mutex.general-21) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7464) *Preconditions*: The calling thread owns the mutex[.](#mutex.general-21.sentence-1) [22](#mutex.general-22) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7468) *Effects*: Releases the calling thread's ownership of the mutex[.](#mutex.general-22.sentence-1) [23](#mutex.general-23) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7472) *Return type*: void[.](#mutex.general-23.sentence-1) [24](#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.2 Multi-threaded executions and data races [intro.multithread]") subsequent lock operations that obtain ownership on the same object[.](#mutex.general-24.sentence-1) [25](#mutex.general-25) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7480) *Throws*: Nothing[.](#mutex.general-25.sentence-1) #### [32.6.4.2.2](#thread.mutex.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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};} [1](#thread.mutex.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[.](#thread.mutex.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()[.](#thread.mutex.class-1.sentence-2) [2](#thread.mutex.class-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7516) [*Note [1](#thread.mutex.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[.](#thread.mutex.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[.](#thread.mutex.class-2.sentence-2) These cases typically occur when a reference-counted object contains a mutex that is used to protect the reference count[.](#thread.mutex.class-2.sentence-3) — *end note*] [3](#thread.mutex.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])[.](#thread.mutex.class-3.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#thread.mutex.class-3.sentence-2) [4](#thread.mutex.class-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7531) [*Note [2](#thread.mutex.class-note-2)*: A program can deadlock if the thread that owns a mutex object callslock() on that object[.](#thread.mutex.class-4.sentence-1) If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition might be observed[.](#thread.mutex.class-4.sentence-2) — *end note*] [5](#thread.mutex.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[.](#thread.mutex.class-5.sentence-1) #### [32.6.4.2.3](#thread.mutex.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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native handles")};} [1](#thread.mutex.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[.](#thread.mutex.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[.](#thread.mutex.recursive-1.sentence-2) [2](#thread.mutex.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])[.](#thread.mutex.recursive-2.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties of classes"))[.](#thread.mutex.recursive-2.sentence-2) [3](#thread.mutex.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[.](#thread.mutex.recursive-3.sentence-1) It is unspecified how many levels of ownership may be acquired by a single thread[.](#thread.mutex.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[.](#thread.mutex.recursive-3.sentence-3) A thread shall call unlock() once for each level of ownership acquired by calls tolock() and try_lock()[.](#thread.mutex.recursive-3.sentence-4) Only when all levels of ownership have been released may ownership be acquired by another thread[.](#thread.mutex.recursive-3.sentence-5) [4](#thread.mutex.recursive-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7589) The behavior of a program is undefined if - [(4.1)](#thread.mutex.recursive-4.1) it destroys a recursive_mutex object owned by any thread or - [(4.2)](#thread.mutex.recursive-4.2) a thread terminates while owning a recursive_mutex object[.](#thread.mutex.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.1 General [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.5 Class template duration [time.duration]"), and abs_time denotes an object of an instantiation of [time_point](time.point "30.6 Class 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.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements ([[thread.req.lockable.timed]](thread.req.lockable.timed "32.2.5.4 Cpp17TimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing 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(); templatebool try_lock_for(const chrono::duration& rel_time); templatebool try_lock_until(const chrono::time_point& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.3 Timed mutex types"))[.](#thread.timedmutex.class-2.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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; templatebool try_lock_for(const chrono::duration& rel_time); templatebool try_lock_until(const chrono::time_point& abs_time); void unlock(); using native_handle_type = *implementation-defined*; // see [[thread.req.native]](thread.req.native "32.2.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.3 Timed mutex types"))[.](#thread.timedmutex.recursive-2.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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.1 General [thread.sharedmutex.requirements.general]")[.](#thread.sharedmutex.requirements.general-1.sentence-1) Shared mutex types meet the requirements of mutex types ([[thread.mutex.requirements.mutex]](#mutex "32.6.4.2 Mutex 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.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements ([[thread.req.lockable.shared]](thread.req.lockable.shared "32.2.5.5 Cpp17SharedLockable 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]](#mutex "32.6.4.2 Mutex types"), shared mutex types provide a[*shared lock*](#def:shared_lock "32.6.4.4.1 General [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.2 Multi-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.2 Exceptions"))[.](#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.2 Multi-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.2 Multi-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.3 Native handles") native_handle_type native_handle(); // see [[thread.req.native]](thread.req.native "32.2.3 Native 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.4 Shared mutex types"))[.](#thread.sharedmutex.class-2.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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.1 General [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.3 Timed mutex types")), shared mutex types ([[thread.sharedmutex.requirements]](#thread.sharedmutex.requirements "32.6.4.4 Shared 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.5 Class template duration")), andabs_time denotes an object of an instantiation of[time_point](time.point "30.6 Class 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.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements ([[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed "32.2.5.6 Cpp17SharedTimedLockable 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.4 Timing 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.2 Multi-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.4 Timing 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.4 Timing 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.2 Multi-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.4 Timing 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(); templatebool try_lock_for(const chrono::duration& rel_time); templatebool try_lock_until(const chrono::time_point& abs_time); void unlock(); // shared ownershipvoid lock_shared(); // blockingbool try_lock_shared(); templatebool try_lock_shared_for(const chrono::duration& rel_time); templatebool try_lock_shared_until(const chrono::time_point& 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.5 Shared timed mutex types"))[.](#thread.sharedtimedmutex.class-2.sentence-1) It is a standard-layout class ([[class.prop]](class.prop "11.2 Properties 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)