[thread.mutex.requirements.mutex]

# 32 Concurrency support library [[thread]](./#thread)

## 32.6 Mutual exclusion [[thread.mutex]](thread.mutex#requirements.mutex)

### 32.6.4 Mutex requirements [[thread.mutex.requirements]](thread.mutex.requirements#mutex)

#### 32.6.4.2 Mutex types [thread.mutex.requirements.mutex]

#### [32.6.4.2.1](#general) General [[thread.mutex.requirements.mutex.general]](thread.mutex.requirements.mutex.general)

[1](#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[.](#general-1.sentence-1)

They meet the requirements set out in [thread.mutex.requirements.mutex][.](#general-1.sentence-2)

In this description, m denotes an object of a mutex type[.](#general-1.sentence-3)

[*Note [1](#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"))[.](#general-1.sentence-4)

â *end note*]

[2](#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]")[.](#general-2.sentence-1)

If initialization of an object of a mutex type fails,
an exception of type system_error is thrown[.](#general-2.sentence-2)

The mutex types are neither copyable nor movable[.](#general-2.sentence-3)

[3](#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)](#general-3.1)

  resource_unavailable_try_again â if any native handle type manipulated is not available[.](#general-3.1.sentence-1)

- [(3.2)](#general-3.2)

  operation_not_permitted â if the thread does not have the
privilege to perform the operation[.](#general-3.2.sentence-1)

- [(3.3)](#general-3.3)

  invalid_argument â if any native handle type manipulated as part of mutex
construction is incorrect[.](#general-3.3.sentence-1)

[4](#general-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7357)

The implementation provides lock and unlock operations, as described below[.](#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"))[.](#general-4.sentence-2)

The lock and unlock operations on
a single mutex appears to occur in a single total order[.](#general-4.sentence-3)

[*Note [2](#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[.](#general-4.sentence-4)

â *end note*]

[*Note [3](#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[.](#general-4.sentence-5)

â *end note*]

[5](#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](#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[.](#general-6.sentence-1)

[7](#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[.](#general-7.sentence-1)

[8](#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[.](#general-8.sentence-1)

[9](#general-9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7393)

*Postconditions*: The calling thread owns the mutex[.](#general-9.sentence-1)

[10](#general-10)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7397)

*Return type*: void[.](#general-10.sentence-1)

[11](#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"))[.](#general-11.sentence-1)

[12](#general-12)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7405)

*Error conditions*: 

- [(12.1)](#general-12.1)

  operation_not_permitted â if the thread does not have the
privilege to perform the operation[.](#general-12.1.sentence-1)

- [(12.2)](#general-12.2)

  resource_deadlock_would_occur â if the implementation detects
that a deadlock would occur[.](#general-12.2.sentence-1)

[13](#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](#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[.](#general-14.sentence-1)

[15](#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[.](#general-15.sentence-1)

If ownership is not obtained, there is no effect and try_lock() immediately returns[.](#general-15.sentence-2)

An implementation may fail to obtain the lock even if it is not
held by any other thread[.](#general-15.sentence-3)

[*Note [4](#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"))[.](#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[.](#general-15.sentence-5)

[16](#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[.](#general-16.sentence-1)

[*Note [5](#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[.](#general-16.sentence-2)

â *end note*]

[17](#general-17)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7449)

*Return type*: bool[.](#general-17.sentence-1)

[18](#general-18)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7452)

*Returns*: true if ownership was obtained, otherwise false[.](#general-18.sentence-1)

[19](#general-19)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7456)

*Throws*: Nothing[.](#general-19.sentence-1)

[20](#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](#general-21)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7464)

*Preconditions*: The calling thread owns the mutex[.](#general-21.sentence-1)

[22](#general-22)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7468)

*Effects*: Releases the calling thread's ownership of the mutex[.](#general-22.sentence-1)

[23](#general-23)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7472)

*Return type*: void[.](#general-23.sentence-1)

[24](#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[.](#general-24.sentence-1)

[25](#general-25)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7480)

*Throws*: Nothing[.](#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.requirements "32.6.4 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.requirements "32.6.4 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)
