This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++14 status.
condition_variable::wait()Section: 32.7.4[thread.condition.condvar], 32.7.5[thread.condition.condvarany]Status:C++14Submitter: Pete BeckerOpened: 2012-03-06Last modified: 2015-10-03
Priority:Not Prioritized
View all otherissues in [thread.condition.condvar].
View all issues withC++14 status.
Discussion:
condition_varible::wait() (and, presumably,condition_variable_any::wait(), although I haven't looked at it) says that it callslock.unlock(), and ifcondition_variable::wait() exits by an exception it callslock.lock() on the way out. But if the initial call tolock.unlock() threw an exception, does it make sense to calllock.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 callslock.lock(). Iflock.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 tolock.lock() is all that's required. But a more natural reading is that wait has to calllock.lock() again, even though it already failed.
lock.unlock() and the final call tolock.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 tolock fails -- what can you do? This is an odd state as wehad it locked before was called wait. Maybe we should callterminate as we cannot meet the post-conditions. We could throw a different exception.
Hans: callingterminate 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 callterminate if the lock cannot be reacquired.
Pablo: Can we change the wording to 'leaves the mutex locked' ?
Hans: so if theunlock 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 aRemarks element for the special"If the function fails to meet the postcondition..." wording and applies this to the proposedwording.
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 functionscope.-?-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_errorwhen 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_errorwhen 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_errorwhen 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_errorwhen 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_errorwhen 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_errorwhen 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 functionscope.-?-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]lockis locked by the calling thread.-12-Throws:Nothing.system_errorwhen 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]lockis locked by the calling thread.[…]-18-Throws:timeout-related exceptions (30.2.4).system_errorwhen 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:lockis locked by the calling thread.[…]-23-Throws:timeout-related exceptions (30.2.4).system_errorwhen an exception is required (30.2.2) or-24-Error conditions:
equivalent error condition fromlock.lock()orlock.unlock().