Section: 32.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 atime_point
to implement thewait_for
functions.For example, on POSIX systems
sleep_for
can be implemented in terms ofnanosleep
which takes only a duration in terms of nanoseconds. The current working paper does not describesleep_for
in terms ofsleep_until
. And paragraph 2 of 32.2.4 [thread.req.timing] has the words strongly encouraging implementations to use monotonic clocks forsleep_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
andtry_lock_for
is also appropriate forwait_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 32.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 orlock.mutex()
returns the same value for each of thelock
arguments supplied by all concurrently waiting threads (viawait
,wait_for
orwait_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 tonotify_all()
, by the elapsed timerel_time
passing (32.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 byrel_time
has elapsed, otherwisetrue
.[ 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()
orlock.unlock()
.
Change 32.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 orlock.mutex()
returns the same value for each of thelock
arguments supplied by all concurrently waiting threads (viawait
,wait_for
orwait_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 ofpred()
istrue
.- 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 tonotify_all()
, by the elapsed timerel_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()
returnstrue
or when the time duration specified byrel_time
has elapsed.27 [Note: There is no blocking if
pred()
is initiallytrue
, 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()
orlock.unlock()
.
Change 32.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 tonotify_all()
, by the elapsed timerel_time
passing (32.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 byrel_time
has elapsed, otherwisetrue
.Throws:
std::system_error
when the returned value, effects, or postcondition cannot be achieved.Error conditions:
- equivalent error condition from
lock.lock()
orlock.unlock()
.
Change 32.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 orlock.mutex()
returns the same value for each of thelock
arguments supplied by all concurrently waiting threads (viawait
,wait_for
orwait_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 ofpred()
istrue
.- 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 tonotify_all()
, by the elapsed timerel_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()
returnstrue
or when the time duration specified byrel_time
has elapsed.24 [Note: There is no blocking if
pred()
is initiallytrue
, 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()
orlock.unlock()
.