Title
Monotonic Clock is Conditionally Supported?
Status
c++11
Section
[thread.condition]
Submitter
Pete Becker

Created on 2008-06-23.00:00:00 last changed 154 months ago

Messages

Date: 2010-10-21.18:28:33

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().
Date: 2009-07-21.00:00:00

[ 2009-07-21 Beman added the requested wording changes to 962. ]

Date: 2010-10-21.18:28:33

[ 2009-07 Frankfurt: ]

Beman will send some suggested wording changes to Howard.

Move to Ready.

Date: 2010-10-21.18:28:33

[ 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 [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.

Date: 2010-10-21.18:28:33

[ 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.

Date: 2008-06-23.00:00:00

Related to 958, 959.

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?

History
Date User Action Args
2011-08-23 20:07:26adminsetstatus: wp -> c++11
2010-10-21 18:28:33adminsetmessages: + msg4085
2010-10-21 18:28:33adminsetmessages: + msg4084
2010-10-21 18:28:33adminsetmessages: + msg4083
2010-10-21 18:28:33adminsetmessages: + msg4082
2010-10-21 18:28:33adminsetmessages: + msg4081
2008-06-23 00:00:00admincreate