This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 1268. The Mutex requirements in 30.4.1 and 30.4.2 are wrong

Section: 32.5 [thread.mutex] Status: Resolved Submitter: Anthony Williams Opened: 2009-11-17 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [thread.mutex].

View all issues with Resolved status.

Discussion:

The `Mutex` requirements in 32.5.4 [thread.mutex.requirements] and 32.5.4.3 [thread.timedmutex.requirements] confuse the requirements on the behaviour of `std::mutex` et al with the requirements on `Lockable` types for use with `std::unique_lock`, `std::lock_guard` and `std::condition_variable_any`.

[ 2010 Pittsburgh: ]

> Concepts of threads chapter and issue presentation are: Lockable < Mutex < TimedMutex and Lockable < TimedLockable < TimedMutex.

> Typo in failed deletion of Mutex in 30.4.4 p4 edits.

> Lockable requirements are too weak for condition_variable_any, but the Mutex requirements are too strong.

> Need subset of Lockable requirements for condition_variable_any that does not include try_lock. E.g. CvLockable < Lockable.

> Text needs updating to recent draft changes.

> Needs to specify exception behavior in Lockable.

> The current standard is fine for what it says, but it places requirements that are too strong on authors of mutexes and locks.

> Move to open status. Suggest Anthony look at condition_variable_any requirements. Suggest Anthony refine requirements/concepts categories.

> Related to 964 and 966

[ 2010-03-28 Daniel synced with N3092. ]

[ 2010-10-25 Daniel adds: ]

> Accepting n3130 would solve this issue.

[ 2010-11 Batavia: ]

> Resolved by adopting n3197.

Proposed resolution:

Add a new section to 32.2 [thread.req] after 32.2.4 [thread.req.timing] as follows:

> 30.2.5 Requirements for Lockable types

> The standard library templates `unique_lock` (32.5.5.4 [thread.lock.unique]), `lock_guard` (32.5.5.2 [thread.lock.guard]), `lock`, `try_lock` (32.5.6 [thread.lock.algorithm]) and `condition_variable_any` (32.6.5 [thread.condition.condvarany]) all operate on user-supplied `Lockable` objects. Such an object must support the member functions specified for either the `Lockable` Requirements or the `TimedLockable` requirements as appropriate to acquire or release ownership of a `lock` by a given `thread`. [Note: the nature of any lock ownership and any synchronization it may entail are not part of these requirements. — end note]

> 30.2.5.1 Lockable Requirements

> In order to qualify as a `Lockable` type, the following expressions must be supported, with the specified semantics, where `m` denotes a value of type `L` that supports the `Lockable`:

> The expression `m.lock()` shall be well-formed and have the following semantics:

> Effects:
>   Block until a lock can be acquired for the current thread.
> Return type:
>   `void`

> The expression `m.try_lock()` shall be well-formed and have the following semantics:

> Effects:
>   Attempt to acquire a lock for the current thread without blocking.
> Return type:
>   `bool`
> Returns:
>   `true` if the lock was acquired, `false` otherwise.

> The expression `m.unlock()` shall be well-formed and have the following semantics:

> Effects:
>   Release a lock on `m` held by the current thread.
> Return type:
>   `void`
> Throws:
>   Nothing if the current thread holds a lock on `m`.

> 30.2.5.2 `TimedLockable` Requirements

> For a type to qualify as `TimedLockable` it must meet the `Lockable` requirements, and additionally the following expressions must be well-formed, with the specified semantics, where `m` is an instance of a type `TL` that supports the `TimedLockable` requirements, `rel_time` denotes instantiation of `duration` (27.5 [time.duration]) and `abs_time` denotes an instantiation of `time_point` (27.6 [time.point])

> The expression `m.try_lock_for(rel_time)` shall be well-formed and have the following semantics:

> Effects:
>   Attempt to acquire a lock for the current thread within the specified time period.
> Return type:
>   `bool`
> Returns:
>   `true` if the lock was acquired, `false` otherwise.

> The expression `m.try_lock_until(abs_time)` shall be well-formed and have the following semantics:

> Effects:
>   Attempt to acquire a lock for the current thread before the specified point in time.
> Return type:
>   `bool`
> Returns:
>   `true` if the lock was acquired, `false` otherwise.

Replace 32.5.4 [thread.mutex.requirements] paragraph 2 with the following:

> 2 This section describes requirements on template argument types used to instantiate templates defined in the mutex types supplied by the C++ standard library. The template definitions in the C++ standard library refer These types shall conform to the named `Mutex` requirements whose details are set out below. In this description, `m` is an object of a `Mutex` type one of the standard library mutex types `std::mutex`, `std::recursive_mutex`, `std::timed_mutex` or `std::recursive_timed_mutex`..

Add the following paragraph after 32.5.4 [thread.mutex.requirements] paragraph 2:

> A `Mutex` type shall conform to the `Lockable` requirements (30.2.5.1).

Replace 32.5.4.3 [thread.timedmutex.requirements] paragraph 1 with the following:

> The C++ standard library `TimedMutex` types `std::timed_mutex` and `std::recursive_timed_mutex` A `TimedMutex` type shall meet the requirements for a `Mutex` type. In addition, it they shall meet the requirements set out in this Clause 30.4.2 below, where `rel_time` denotes an instantiation of `duration` (27.5 [time.duration]) and `abs_time` denotes an instantiation of `time_point` (27.6 [time.point]).

Add the following paragraph after 32.5.4.3 [thread.timedmutex.requirements] paragraph 1:

> A `TimedMutex` type shall conform to the `TimedLockable` requirements (30.2.5.1).

Add the following paragraph following 32.5.5.2 [thread.lock.guard] paragraph 1:

> The supplied `Mutex` type shall meet the `Lockable` requirements (30.2.5.1).

Add the following paragraph following 32.5.5.4 [thread.lock.unique] paragraph 1:

> The supplied `Mutex` type shall meet the `Lockable` requirements (30.2.5.1). `unique_lock<Mutex>` meets the `Lockable` requirements. If `Mutex` meets the `TimedLockable` requirements (30.2.5.2) then `unique_lock<Mutex>` also meets the `TimedLockable` requirements.

Replace the use of "mutex" or "mutex object" with "lockable object" throughout clause 32.5.5 [thread.lock] paragraph 1:

> 1 A lock is an object that holds a reference to a mutex lockable object and may unlock the mutex lockable object during the lock's destruction (such as when leaving block scope). A thread of execution may use a lock to aid in managing mutex ownership of a lockable object in an exception safe manner. A lock is said to own a mutex lockable object if it is currently managing the ownership of that mutex lockable object for a thread of execution. A lock does not manage the lifetime of the mutex lockable object it references. [ Note: Locks are intended to ease the burden of unlocking the mutex lockable object under both normal and exceptional circumstances. — end note ]

32.5.5 [thread.lock] paragaph 2:

> 2 Some lock constructors take tag types which describe what should be done with the mutex lockable object during the lock's constuction.

32.5.5.2 [thread.lock.guard] paragaph 1:

> 1 An object of type `lock_guard` controls the ownership of a mutex lockable object within a scope. A `lock_guard` object maintains ownership of a mutex lockable object throughout the `lock_guard` object's lifetime. The behavior of a program is undefined if the mutex lockable object referenced by `pm` does not exist for the entire lifetime (3.8) of the `lock_guard` object. `Mutex` shall meet the `Lockable` requirements (30.2.5.1).

32.5.5.4 [thread.lock.unique] paragaph 1:

> 1 An object of type `unique_lock` controls the ownership of a mutex lockable object within a scope. Mutex o Ownership of the lockable object may be acquired at construction or after construction, and may be transferred, after acquisition, to another `unique_lock` object. Objects of type `unique_lock` are not copyable but are movable. The behavior of a program is undefined if the contained pointer `pm` is not null and the mutex pointed to by `pm` does not exist for the entire remaining lifetime (3.8) of the `unique_lock` object. `Mutex` shall meet the `Lockable` requirements (30.2.5.1).

Add the following to the precondition of `unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time)` in 32.5.5.4.2 [thread.lock.unique.cons] paragraph 18:

>     template <class Clock, class Duration>
>       unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);

> > 18 Requires: If `mutex_type` is not a recursive mutex the calling thread does not own the mutex. The supplied `mutex_type` type shall meet the `TimedLockable` requirements (30.2.5.2).

Add the following to the precondition of `unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time)` in 32.5.5.4.2 [thread.lock.unique.cons] paragraph 22

> 22 Requires: If `mutex_type` is not a recursive mutex the calling thread does not own the mutex. The supplied `mutex_type` type shall meet the `TimedLockable` requirements (30.2.5.2).

Add the following as a precondition of `bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)` before 32.5.5.4.3 [thread.lock.unique.locking] paragraph 8

>     template <class Clock, class Duration>
>       bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);

> > Requires: The supplied `mutex_type` type shall meet the `TimedLockable` requirements (30.2.5.2).

Add the following as a precondition of `bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)` before 32.5.5.4.3 [thread.lock.unique.locking] paragraph 12

>     template <class Rep, class Period>
>       bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);

> > Requires: The supplied `mutex_type` type shall meet the `TimedLockable` requirements (30.2.5.2).

Replace 32.5.6 [thread.lock.algorithm] p1 with the following:

>     template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);

> > 1 Requires: Each template parameter type shall meet the `Mutex Lockable` requirements (30.2.5.1)., except that a call to `try_lock()` may throw an exception. [Note: The `unique_lock` class template meets these requirements when suitably instantiated. — end note]

Replace 32.5.6 [thread.lock.algorithm] p4 with the following:

>     template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);

> > 4 Requires: Each template parameter type shall meet the `MutexMutex Lockable` requirements (30.2.5.1)., except that a call to `try_lock()` may throw an exception. [Note: The `unique_lock` class template meets these requirements when suitably instantiated. — end note]

Replace 32.6.5 [thread.condition.condvarany] paragraph 1 with:

> 1 A `Lock` type shall meet the requirements for a `Mutex` type `Lockable` requirements (30.2.5.1), except that `try_lock` is not required. [Note: All of the standard mutex types meet this requirement. — end note]