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.
Section: 33.6 [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 33.6.4 [thread.mutex.requirements] and 33.6.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.
[ 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 33.2 [thread.req] after 33.2.4 [thread.req.timing] as follows:
30.2.5 Requirements for Lockable types
The standard library templates unique_lock (33.6.5.4 [thread.lock.unique]), lock_guard (33.6.5.2 [thread.lock.guard]), lock, try_lock (33.6.6 [thread.lock.algorithm]) and condition_variable_any (33.7.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 (29.5 [time.duration]) and abs_time denotes an instantiation of time_point (29.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 33.6.4 [thread.mutex.requirements] paragraph 2 with the following:
2 This section describes requirements on
template argument types used to instantiate templates defined inthe mutex types supplied by the C++ standard library.The template definitions in the C++ standard library referThese types shall conform to the named Mutex requirements whose details are set out below. In this description, m is an object ofa Mutex typeone of the standard library mutex types std::mutex, std::recursive_mutex, std::timed_mutex or std::recursive_timed_mutex..
Add the following paragraph after 33.6.4 [thread.mutex.requirements] paragraph 2:
A Mutex type shall conform to the Lockable requirements (30.2.5.1).
Replace 33.6.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 typeshall meet the requirements for a Mutex type. In addition,itthey shall meet the requirements set outin this Clause 30.4.2below, where rel_time denotes an instantiation of duration (29.5 [time.duration]) and abs_time denotes an instantiation of time_point (29.6 [time.point]).
Add the following paragraph after 33.6.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 33.6.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 33.6.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 33.6.5 [thread.lock] paragraph 1:
1 A lock is an object that holds a reference to a
mutexlockable object and may unlock themutexlockable object during the lock's destruction (such as when leaving block scope). A thread of execution may use a lock to aid in managingmutexownership of a lockable object in an exception safe manner. A lock is said to own amutexlockable object if it is currently managing the ownership of thatmutexlockable object for a thread of execution. A lock does not manage the lifetime of themutexlockable object it references. [ Note: Locks are intended to ease the burden of unlocking themutexlockable object under both normal and exceptional circumstances. — end note ]
33.6.5 [thread.lock] paragaph 2:
2 Some lock constructors take tag types which describe what should be done with the
mutexlockable object during the lock's constuction.
33.6.5.2 [thread.lock.guard] paragaph 1:
1 An object of type lock_guard controls the ownership of a
mutexlockable object within a scope. A lock_guard object maintains ownership of amutexlockable object throughout the lock_guard object's lifetime. The behavior of a program is undefined if themutexlockable 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).
33.6.5.4 [thread.lock.unique] paragaph 1:
1 An object of type unique_lock controls the ownership of a
mutexlockable object within a scope.MutexoOwnership 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 33.6.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 33.6.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 33.6.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 33.6.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 33.6.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
MutexLockable 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 33.6.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 Mutex
MutexLockable 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 33.7.5 [thread.condition.condvarany] paragraph 1 with:
1 A Lock type shall meet the
requirements for a Mutex typeLockable requirements (30.2.5.1), except that try_lock is not required. [Note: All of the standard mutex types meet this requirement. — end note]