Proposed resolution:
Change [thread.condition.condvar], p21-22:
template <class Rep, class Period> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);Precondition: lock is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting threads (via wait, wait_for or wait_until).
21 Effects:
wait_until(lock, chrono::monotonic_clock::now() + rel_time)
- 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 to notify_all(), by the elapsed time rel_time passing ([thread.req.timing]), or spuriously.
- If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.
Postcondition: lock is locked by the calling thread.
22 Returns: false if the call is returning because the time duration specified by rel_time has elapsed, otherwise true.
This part of the wording may conflict with 857 in detail, but does not do so in spirit. If both issues are accepted, there is a logical merge. Throws: std::system_error when the effects or postcondition cannot be achieved.
Error conditions:
- operation_not_permitted -- if the thread does not own the lock.
- equivalent error condition from lock.lock() or lock.unlock().
Change [thread.condition.condvar], p26-p29:
template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);Precondition: lock is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting threads (via wait, wait_for or wait_until).
26 Effects:
wait_until(lock, chrono::monotonic_clock::now() + rel_time, std::move(pred))
- Executes a loop: Within the loop the function first evaluates pred() and exits the loop if the result of pred() is true.
- Atomically calls lock.unlock() and blocks on *this.
- When unblocked, calls lock.lock() (possibly blocking on the lock).
- The function will unblock when signaled by a call to notify_one(), a call to notify_all(), by the elapsed time rel_time passing (30.1.4 [thread.req.timing]), or spuriously.
- If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.
- The loop terminates when pred() returns true or when the time duration specified by rel_time has elapsed.
27 [Note: There is no blocking if pred() is initially true, even if the timeout has already expired. -- end note]
Postcondition: lock is locked by the calling thread.
28 Returns: pred()
29 [Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. -- end note]
Throws: std::system_error when the effects or postcondition cannot be achieved.
Error conditions:
- operation_not_permitted -- if the thread does not own the lock.
- equivalent error condition from lock.lock() or lock.unlock().
Change [thread.condition.condvarany], p18-19:
template <class Lock, class Rep, class Period> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);18 Effects:
wait_until(lock, chrono::monotonic_clock::now() + rel_time)
- 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 to notify_all(), by the elapsed time rel_time passing ([thread.req.timing]), or spuriously.
- If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.
Postcondition: lock is locked by the calling thread.
19 Returns: false if the call is returning because the time duration specified by rel_time has elapsed, otherwise true.
Throws: std::system_error when the returned value, effects, or postcondition cannot be achieved.
Error conditions:
- equivalent error condition from lock.lock() or lock.unlock().
Change [thread.condition.condvarany], p23-p26:
template <class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);Precondition: lock is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting threads (via wait, wait_for or wait_until).
23 Effects:
wait_until(lock, chrono::monotonic_clock::now() + rel_time, std::move(pred))
- Executes a loop: Within the loop the function first evaluates pred() and exits the loop if the result of pred() is true.
- Atomically calls lock.unlock() and blocks on *this.
- When unblocked, calls lock.lock() (possibly blocking on the lock).
- The function will unblock when signaled by a call to notify_one(), a call to notify_all(), by the elapsed time rel_time passing (30.1.4 [thread.req.timing]), or spuriously.
- If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.
- The loop terminates when pred() returns true or when the time duration specified by rel_time has elapsed.
24 [Note: There is no blocking if pred() is initially true, even if the timeout has already expired. -- end note]
Postcondition: lock is locked by the calling thread.
25 Returns: pred()
26 [Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. -- end note]
Throws: std::system_error when the effects or postcondition cannot be achieved.
Error conditions:
- operation_not_permitted -- if the thread does not own the lock.
- equivalent error condition from lock.lock() or lock.unlock().