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.
Section: 33.7 [thread.condition] Status: C++11 Submitter: Pete Becker Opened: 2008-06-23 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [thread.condition].
View all issues with C++11 status.
Discussion:
N2661 says that there is a class named monotonic_clock. It also says that this name may be a synonym for system_clock, and that it's conditionally supported. So the actual requirement is that it can be monotonic or not, and you can tell by looking at is_monotonic, or it might not exist at all (since it's conditionally supported). Okay, maybe too much flexibility, but so be it.
A problem comes up in the threading specification, where several variants of wait_for explicitly use monotonic_clock::now(). What is the meaning of an effects clause that says
wait_until(lock, chrono::monotonic_clock::now() + rel_time)
when monotonic_clock is not required to exist?
[ San Francisco: ]
Nick: maybe instead of saying that chrono::monotonic_clock is conditionally supported, we could say that it's always there, but not necessarily supported..
Beman: I'd prefer a typedef that identifies the best clock to use for wait_for locks.
Tom: combine the two concepts; create a duration clock type, but keep the is_monotonic test.
Howard: if we create a duration_clock type, is it a typedef or an entirely true type?
There was broad preference for a typedef.
Move to Open. Howard to provide wording to add a typedef for duration_clock and to replace all uses of monotonic_clock in function calls and signatures with duration_clock.
[ Howard notes post-San Francisco: ]
After further thought I do not believe that creating a duration_clock typedef is the best way to proceed. An implementation may not need to use a time_point to implement the wait_for functions.
For example, on POSIX systems sleep_for can be implemented in terms of nanosleep which takes only a duration in terms of nanoseconds. The current working paper does not describe sleep_for in terms of sleep_until. And paragraph 2 of 33.2.4 [thread.req.timing] has the words strongly encouraging implementations to use monotonic clocks for sleep_for:
2 The member functions whose names end in _for take an argument that specifies a relative time. Implementations should use a monotonic clock to measure time for these functions.
I believe the approach taken in describing the effects of sleep_for and try_lock_for is also appropriate for wait_for. I.e. these are not described in terms of their _until variants.
[ 2009-07 Frankfurt: ]
Beman will send some suggested wording changes to Howard.
Move to Ready.
[ 2009-07-21 Beman added the requested wording changes to 962. ]
Proposed resolution:
Change 33.7.4 [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 (33.2.4 [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 33.7.4 [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 33.7.5 [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 (33.2.4 [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 33.7.5 [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().