This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
condition_variable::wait()
Section: 32.7.4 [thread.condition.condvar], 32.7.5 [thread.condition.condvarany] Status: C++14 Submitter: Pete Becker Opened: 2012-03-06 Last modified: 2015-10-03
Priority: Not Prioritized
View all other issues in [thread.condition.condvar].
View all issues with C++14 status.
Discussion:
condition_varible::wait()
(and, presumably, condition_variable_any::wait()
, although
I haven't looked at it) says that it calls lock.unlock()
, and if condition_variable::wait()
exits by an exception it calls lock.lock()
on the way out. But if the initial call to
lock.unlock()
threw an exception, does it make sense to call lock.lock()
? We simply
don't know the state of that lock object, and it's probably better not to touch it.
wait()
call has been unblocked, it calls lock.lock()
. If lock.lock()
throws an exception, what happens? The requirement is:
If the function exits via an exception,
lock.lock()
shall be called prior to exiting the function scope.
That can be read in two different ways. One way is as if it said "lock.lock()
shall have been called …",
i.e. the original, failed, call to lock.lock()
is all that's required. But a more natural reading is
that wait has to call lock.lock()
again, even though it already failed.
lock.unlock()
and the final call to lock.lock()
. Each one should have its own requirement.
Lumping them together muddles things.
[2012, Portland: move to Open]
Pablo: unlock
failing is easy -- the call leaves it locked.
The second case, trying to lock
fails -- what can you do?
This is an odd state as we had it locked before was called wait.
Maybe we should call terminate
as we cannot meet the post-conditions.
We could throw a different exception.
Hans: calling terminate
makes sense as we're likely to call it soon anyway
and at least we have some context.
Detlef: what kind of locks might be being used?
Pablo: condition variables are 'our' locks so this is less of a problem.
condition_variable_any
might be more problematic.
The general direction is to call terminate
if the lock cannot be reacquired.
Pablo: Can we change the wording to 'leaves the mutex locked' ?
Hans: so if the unlock
throws we simply propagate the exception.
Move the issue to open and add some formal wording at a later time.
[2013-09 Chicago: Resolved]
Detlef improves wording. Daniel suggests to introduce a Remarks element for the special "If the function fails to meet the postcondition..." wording and applies this to the proposed wording.
Proposed resolution:
This wording is relative to N3691.
Edit 32.7.4 [thread.condition.condvar] as indicated:
void wait(unique_lock<mutex>& lock);[…]
-10- Effects:
Atomically calls
lock.unlock()
and blocks on*this
.When unblocked, calls
lock.lock()
(possibly blocking on the lock), then returns.The function will unblock when signaled by a call to
notify_one()
or a call tonotify_all()
, or spuriously.
If the function exits via an exception,lock.lock()
shall be called prior to exiting the function scope.-?- Remarks: If the function fails to meet the postcondition,
-11- Postcondition:std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note]lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. -12- Throws: Nothing.system_error
when an exception is required (30.2.2)-13- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred);[…]
-?- Remarks: If the function fails to meet the postcondition,std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note] -16- Postcondition:lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. -17- Throws:timeout-related exceptions (30.2.4)system_error
when an exception is required (30.2.2),,or any exception thrown bypred
.-18- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time);[…]
-20- Effects:
[…]
If the function exits via an exception,
lock.lock()
shall be called prior to exiting the functionscope.-?- Remarks: If the function fails to meet the postcondition,
-21- Postcondition:std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note]lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. […] -23- Throws:timeout-related exceptions (30.2.4).system_error
when an exception is required (30.2.2) or-24- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);[…]
-?- Remarks: If the function fails to meet the postcondition,std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note] -28- Postcondition:lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. […] -29- Throws:timeout-related exceptions (30.2.4).system_error
when an exception is required (30.2.2) or-30- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);[…]
-?- Remarks: If the function fails to meet the postcondition,std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note] -33- Postcondition:lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. […] -35- Throws:timeout-related exceptions (30.2.4)system_error
when an exception is required (30.2.2),,or any exception thrown bypred
.-36- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);[…]
-?- Remarks: If the function fails to meet the postcondition,std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note] -40- Postcondition:lock.owns_lock()
is true andlock.mutex()
is locked by the calling thread. […] -42- Throws:timeout-related exceptions (30.2.4)system_error
when an exception is required (30.2.2),,or any exception thrown bypred
.-43- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.
Edit 32.7.5 [thread.condition.condvarany] as indicated:
template<class Lock> void wait(Lock& lock);[…]
-10- Effects:
Atomically calls
lock.unlock()
and blocks on*this
.When unblocked, calls
lock.lock()
(possibly blocking on the lock) and returns.The function will unblock when signaled by a call to
notify_one()
, a call tonotify_all()
, or spuriously.
If the function exits via an exception,lock.lock()
shall be called prior to exiting the function scope.-?- Remarks: If the function fails to meet the postcondition,
-11- Postcondition:std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note]lock
is locked by the calling thread. -12- Throws: Nothing.system_error
when an exception is required (30.2.2)-13- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);[…]
-15- Effects:
[…]
If the function exits via an exception,
lock.lock()
shall be called prior to exiting the functionscope.-?- Remarks: If the function fails to meet the postcondition,
-16- Postcondition:std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note]lock
is locked by the calling thread. […] -18- Throws:timeout-related exceptions (30.2.4).system_error
when an exception is required (30.2.2) or-19- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.template <class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);[…]
-?- Remarks: If the function fails to meet the postcondition,std::terminate()
shall be called (14.6.2 [except.terminate]). [Note: This can happen if the re-locking of the mutex throws an exception. — end note] -22- Postcondition:lock
is locked by the calling thread. […] -23- Throws:timeout-related exceptions (30.2.4).system_error
when an exception is required (30.2.2) or-24- Error conditions:
equivalent error condition fromlock.lock()
orlock.unlock()
.