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.

### 859. Monotonic Clock is Conditionally Supported?

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:

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?

[ 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()`.