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

16 KiB

[thread.mutex.requirements.mutex]

32 Concurrency support library [thread]

32.6 Mutual exclusion [thread.mutex]

32.6.4 Mutex requirements [thread.mutex.requirements]

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

32.6.4.2.1 General [thread.mutex.requirements.mutex.general]

1

#

The mutex types are the standard library types mutex,recursive_mutex, timed_mutex, recursive_timed_mutex,shared_mutex, and shared_timed_mutex.

They meet the requirements set out in [thread.mutex.requirements.mutex].

In this description, m denotes an object of a mutex type.

[Note 1:

The mutex types meet the Cpp17Lockable requirements ([thread.req.lockable.req]).

— end note]

2

#

The mutex types meet Cpp17DefaultConstructible and Cpp17Destructible.

If initialization of an object of a mutex type fails, an exception of type system_error is thrown.

The mutex types are neither copyable nor movable.

3

#

The error conditions for error codes, if any, reported by member functions of the mutex types are as follows:

  • (3.1)

    resource_unavailable_try_again — if any native handle type manipulated is not available.

  • (3.2)

    operation_not_permitted — if the thread does not have the privilege to perform the operation.

  • (3.3)

    invalid_argument — if any native handle type manipulated as part of mutex construction is incorrect.

4

#

The implementation provides lock and unlock operations, as described below.

For purposes of determining the existence of a data race, these behave as atomic operations ([intro.multithread]).

The lock and unlock operations on a single mutex appears to occur in a single total order.

[Note 2:

This can be viewed as the modification order of the mutex.

— end note]

[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.

— end note]

5

#

The expression m.lock() is well-formed and has the following semantics:

6

#

Preconditions: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling thread does not own the mutex.

7

#

Effects: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread.

8

#

Synchronization: Prior unlock() operations on the same objectsynchronize with ([intro.multithread]) this operation.

9

#

Postconditions: The calling thread owns the mutex.

10

#

Return type: void.

11

#

Throws: system_error when an exception is required ([thread.req.exception]).

12

#

Error conditions:

  • (12.1)

    operation_not_permitted — if the thread does not have the privilege to perform the operation.

  • (12.2)

    resource_deadlock_would_occur — if the implementation detects that a deadlock would occur.

13

#

The expression m.try_lock() is well-formed and has the following semantics:

14

#

Preconditions: If m is of type mutex, timed_mutex,shared_mutex, or shared_timed_mutex, the calling thread does not own the mutex.

15

#

Effects: Attempts to obtain ownership of the mutex for the calling thread without blocking.

If ownership is not obtained, there is no effect and try_lock() immediately returns.

An implementation may fail to obtain the lock even if it is not held by any other thread.

[Note 4:

This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange ([atomics]).

— end note]

An implementation should ensure that try_lock() does not consistently return false in the absence of contending mutex acquisitions.

16

#

Synchronization: If try_lock() returns true, prior unlock() operations on the same object synchronize with this operation.

[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.

— end note]

17

#

Return type: bool.

18

#

Returns: true if ownership was obtained, otherwise false.

19

#

Throws: Nothing.

20

#

The expression m.unlock() is well-formed and has the following semantics:

21

#

Preconditions: The calling thread owns the mutex.

22

#

Effects: Releases the calling thread's ownership of the mutex.

23

#

Return type: void.

24

#

Synchronization: This operation synchronizes with subsequent lock operations that obtain ownership on the same object.

25

#

Throws: Nothing.

32.6.4.2.2 Class mutex [thread.mutex.class]

🔗

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] native_handle_type native_handle(); // see [thread.req.native]};}

1

#

The class mutex provides a non-recursive mutex with exclusive ownership semantics.

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().

2

#

[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.

Conforming implementations handle such scenarios correctly, as long as thread A does not access the mutex after the unlock call returns.

These cases typically occur when a reference-counted object contains a mutex that is used to protect the reference count.

— end note]

3

#

The class mutex meets all of the mutex requirements ([thread.mutex.requirements]).

It is a standard-layout class ([class.prop]).

4

#

[Note 2:

A program can deadlock if the thread that owns a mutex object callslock() on that object.

If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition might be observed.

— end note]

5

#

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.

32.6.4.2.3 Class recursive_mutex [thread.mutex.recursive]

🔗

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] native_handle_type native_handle(); // see [thread.req.native]};}

1

#

The class recursive_mutex provides a recursive mutex with exclusive ownership semantics.

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.

2

#

The class recursive_mutex meets all of the mutex requirements ([thread.mutex.requirements]).

It is a standard-layout class ([class.prop]).

3

#

A thread that owns a recursive_mutex object may acquire additional levels of ownership by calling lock() or try_lock() on that object.

It is unspecified how many levels of ownership may be acquired by a single thread.

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.

A thread shall call unlock() once for each level of ownership acquired by calls tolock() and try_lock().

Only when all levels of ownership have been released may ownership be acquired by another thread.

4

#

The behavior of a program is undefined if

it destroys a recursive_mutex object owned by any thread or

a thread terminates while owning a recursive_mutex object.