This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.
condition_variable::time_wait return bool error proneSection: 32.7.4 [thread.condition.condvar] Status: C++11 Submitter: Beman Dawes Opened: 2008-06-13 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [thread.condition.condvar].
View all other issues in [thread.condition.condvar].
View all issues with C++11 status.
Discussion:
The meaning of the bool returned by condition_variable::timed_wait is so
obscure that even the class' designer can't deduce it correctly. Several
people have independently stumbled on this issue.
It might be simpler to change the return type to a scoped enum:
enum class timeout { not_reached, reached };
That's the same cost as returning a bool, but not subject to mistakes. Your example below would be:
if (cv.wait_until(lk, time_limit) == timeout::reached ) throw time_out();
[ Beman to supply exact wording. ]
[ San Francisco: ]
There is concern that the enumeration names are just as confusing, if not more so, as the bool. You might have awoken because of a signal or a spurious wakeup, for example.
Group feels that this is a defect that needs fixing.
Group prefers returning an enum over a void return.
Howard to provide wording.
[ 2009-06-14 Beman provided wording. ]
[ 2009-07 Frankfurt: ]
Move to Ready.
Proposed resolution:
Change Condition variables 32.7 [thread.condition], Header condition_variable synopsis, as indicated:
namespace std {
class condition_variable;
class condition_variable_any;
enum class cv_status { no_timeout, timeout };
}
Change class condition_variable 32.7.4 [thread.condition.condvar] as indicated:
class condition_variable { public: ... template <class Clock, class Duration>boolcv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time); template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template <class Rep, class Period>boolcv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time); template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); ... }; ... template <class Clock, class Duration>boolcv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time);-15- Precondition:
lockis locked by the calling thread, and either
- no other thread is waiting on this
condition_variableobject orlock.mutex()returns the same value for each of thelockarguments supplied by all concurrently waiting threads (viawait,wait_fororwait_until.).-16- 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(),by the current time exceedingifabs_timeClock::now() >= abs_time, or spuriously.- If the function exits via an exception,
lock.unlock()shall be called prior to exiting the function scope.-17- Postcondition:
lockis locked by the calling thread.-18- Returns:
Clock::now() < abs_timecv_status::timeoutif the function unblocked becauseabs_timewas reached, otherwisecv_status::no_timeout.-19- Throws:
std::system_errorwhen the effects or postcondition cannot be achieved.-20- Error conditions:
operation_not_permitted— if the thread does not own the lock.- equivalent error condition from
lock.lock()orlock.unlock().template <class Rep, class Period>boolcv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);-21-
EffectsReturns:wait_until(lock, chrono::monotonic_clock::now() + rel_time)
-22- Returns:falseif the call is returning because the time duration specified byrel_timehas elapsed, otherwisetrue.[ This part of the wording may conflict with 859(i) in detail, but does not do so in spirit. If both issues are accepted, there is a logical merge. ]
template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);-23- Effects:
while (!pred()) if (!wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;-24- Returns:
pred().-25- [Note: The returned value indicates whether the predicate evaluates to
trueregardless of whether the timeout was triggered. — end note].
Change Class condition_variable_any 32.7.5 [thread.condition.condvarany] as indicated:
class condition_variable_any { public: ... template <class Lock, class Clock, class Duration>boolcv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template <class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template <class Lock, class Rep, class Period>boolcv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template <class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); ... }; ... template <class Lock, class Clock, class Duration>boolcv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);-13- 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(),by the current time exceedingifabs_timeClock::now() >= abs_time, or spuriously.- If the function exits via an exception,
lock.unlock()shall be called prior to exiting the function scope.-14- Postcondition:
lockis locked by the calling thread.-15- Returns:
Clock::now() < abs_timecv_status::timeoutif the function unblocked becauseabs_timewas reached, otherwisecv_status::no_timeout.-16- Throws:
std::system_errorwhen the effects or postcondition cannot be achieved.-17- Error conditions:
- equivalent error condition from
lock.lock()orlock.unlock().template <class Lock, class Rep, class Period>boolcv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);-18-
EffectsReturns:wait_until(lock, chrono::monotonic_clock::now() + rel_time)
-19- Returns:falseif the call is returning because the time duration specified byrel_timehas elapsed, otherwisetrue.[ This part of the wording may conflict with 859(i) in detail, but does not do so in spirit. If both issues are accepted, there is a logical merge. ]
template <class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>&rel_timeabs_time, Predicate pred);-20- Effects:
while (!pred()) if (!wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;-21- Returns:
pred().-22- [Note: The returned value indicates whether the predicate evaluates to
trueregardless of whether the timeout was triggered. — end note].