C++ Timeout Specification (original) (raw)
ISO/IEC JTC1 SC22 WG21 N3128 = 10-0118 - 2010-08-19
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
This paper revises FCD comment US 181 and its proposed resolution based on discussions in the August 2010 meeting.
Problem
Solution
Wording
20.10 Time utilities [time]
20.10.1 Clock requirements [time.clock.req]
20.10.5.1 Class system_clock [time.clock.system]20.10.5.2 Class monotonic_clock [time.clock.monotonic]
20.10.5.2 Class steady_clock [time.clock.steady]
20.10.5.3 Class high_resolution_clock [time.clock.hires]
30.2.4 Timing specifications [thread.req.timing]
30.3.2 Namespace this_thread [thread.thread.this]
30.4.2 TimedMutex requirements [thread.timedmutex.requirements]
30.5.1 Class condition_variable [thread.condition.condvar]
30.5.2 Class condition_variable_any [thread.condition.condvarany]
30.6.6 Class template future [futures.unique_future]
30.6.7 Class template shared_future [futures.shared_future]
30.6.8 Class template atomic_future [futures.atomic_future]
Problem
The meaning of clocks and timeouts is poorly defined within the Final Committee Draft when those clocks may be adjusted. Clocks can be adjusted by hours and many network protocols expect responses within seconds. A task regularly scheduled for midnight GMT should execute at midnight even though the clock has been adjusted to eliminate accumulated error. Failure of the standard to be precise about this distinction makes programs effectively unportable.
The root of the problem is that the current definition leaves open disparate implementations that even as implementations increase their quality, separate implementations will not converge on the same behavior.
There will necessarily be some delay in the interrupt response, function return, and scheduling of a thread waking from a timeout. Implementations can reasonably strive to approach zero delay for these activities. So, we call this delay the "quality of implementation".
Separately, there will be some delay due to contention for processor and memory resources. This delay is more under the control of the application programmer and systems administrator than it is under the implementation. So, we call this delay the "quality of management". The tradeoff between resources and responsiveness is necessarily application-dependent.
We can express the actual time of a timeout as the sum of the intended time, the quality of implementation and the quality of management. The remaining problem is to map the given timeout specifications to a common intended time.
If there are no adjustments to the clock time, the intended time may be straightforwardly determined from the manner of specification. In this case, we assume that any difference in durations between reported times and SI units is small, and thus constitutes a measure of the quality of implementation.
The problem arises with the specification of the intended timeout when the clock is adjusted in the middle of the timeout. There are two plausible strategies, the timeout is sensitive to adjustments in the clock time, or it is not. The timeout_until functions have straightforward definitions when they are sensitive to adjustments. The timeout_for functions have straightforward definitions when they are insensitive to adjustments.
Solution
Define timeout_until to respect reported clock time points and define timeout_for to respect real time durations. However, implementation constraints in the short term make a strict definition infeasible. So, instead we encourage such a definition.
A consequence of these definitions is thattimeout_until and timeout_for are not functionally redundant. That is, timeout_until(Clock::now()+3_seconds) is generally not equivalent to timeout_for(3_seconds) when the clock is adjusted in the interval.
The implementation of the timeout definition necessarily depends on a steady clock, one that cannot be adjusted. A monotonic clock is not sufficient. While one could be implicit in the standard, below we make one explicit.
Given a steady clock, the monotonic clock seems to be of marginal utility, and we replace the monotonic clock with the steady clock.
[Note that considered the practice of setting clocks forward in unit tests, and believe that continuing to do so even in timeout_for operations would be reasonable because the tests operate in a virtual world, not in the real world. The definition of time in that world need not be the same as the time in the real world.]
Wording
The proposed wording changes are relative to the Final Committee Draft,N3092.
**Note to the Editor:**This paper should be consistent with N3130 under the assumption that they would both be accepted; any inconsistencies are accidental and unintended.
20.10 Time utilities [time]
Edit within the header synopsis as follows.
// Clocks class system_clock; class monotonic_clock; class steady_clock; class high_resolution_clock;
20.10.1 Clock requirements [time.clock.req]
Edit within table 56 as follows.
.... .... .... C1::is_monotonicconst booltrueif t1 <= t2 is always true, otherwise false. [_Note:_A clock that can be adjusted backwards is not monotonic. —_end note_]C1::is_steady const bool true if the time between clock ticks is constant, otherwise false. C1::now() C1::time_point Returns a time_point object representing the current point in time.
Add a new paragraph 3.
[_Note:_The relative difference in durations between those reported by the given clock and the SI definition is a measure of the quality of implementation. —_end note_]
20.10.5.1 Class system_clock
[time.clock.system]
Edit paragraph 1 as follows.
Objects of class
system_clock
represent wall clock time from the system-wide realtime clock.class system_clock { public: typedef see below rep; typedef ratio<unspecified, unspecified> period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<system_clock> time_point; static const bool is_monotonic = unspecified; static const bool is_steady = unspecified; static time_point now(); // Map to C API static time_t to_time_t(const time_point& t); static time_point from_time_t(time_t t); };
20.10.5.2 Class monotonic_clock
[time.clock.monotonic]
monotonic_clock
[time.clock.monotonic]20.10.5.2 Class steady_clock
[time.clock.steady]
Delete paragraph 1.
Objects of classmonotonic_clock
represent clocks for which values oftime_point
never decrease as physical time advances.monotonic_clock
may be a synonym forsystem_clock
ifsystem_clock::is_monotonic
istrue
.
Edit paragraph 2 as follows.
The classObjects of classmonotonic_clock
is conditionally supported.steady_clock
represent clocks for which values oftime_point
advance at a steady rate relative to real time. That is, the clock may not be adjusted.class monotonic_clock steady_clock { public: typedef unspecified rep; typedef ratio<unspecified, unspecified> period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified> time_point; static const bool is_monotonic = true; static const bool is_steady = true; static time_point now(); };
20.10.5.3 Class high_resolution_clock
[time.clock.hires]
Edit paragraph 1 as follows.
Objects of class
high_resolution_clock
represent clocks with the shortest tick period.high_resolution_clock
may be a synonym forsystem_clock
ormonotonic_clock
steady_clock
.class high_resolution_clock { public: typedef unspecified rep; typedef ratio<unspecified, unspecified> period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified> time_point; static const bool is_monotonic = unspecified; static const bool is_steady = unspecified; static time_point now(); };
30.2.4 Timing specifications [thread.req.timing]
Add a new paragraph after paragraph 1 as follows.
Implementations necessarily have some delay in returning from a timeout. Any overhead in interrupt response, function return, and scheduling induces a "quality of implementation" delay, expressed as duration Di. Ideally, this delay would be zero. Further, any contention for processor and memory resources induces a "quality of management" delay, expressed as duration Dm. The delay durations may vary from timeout to timeout, but in all cases shorter is better.
Edit paragraph 2 as follows.
The member functions whose names end in
_for
take an argument that specifies arelative timeduration. These functions produce relative timeouts. Implementationsshouldshoulduse amonotonicsteady clock to measure time for these functions.[_Note:_Implementations are not required to use a monotonic clock because such a clock may not be available. —_end note_][_Footnote:_All implementations for which standard time units are meaningful must necessarily have a steady clock within their hardware implementation. —_end footnote_] Given a duration argument Dt, the real-time duration of the timeout is Dt+Di+Dm.
Add a new paragraph after paragraph 2 as follows.
The member functions whose names end in
_until
take an argument that specifies a time point. These functions produce absolute timeouts. Implementations should use the clock specified in the time point to measure time for these functions. Given a clock time point argument Ct, the clock time point of the return from timeout should be Ct+Di+Dm when the clock is not adjusted during the timeout. If the clock is adjusted to the time Ca during the timeout, the behavior of functions with an absolute timeout should be as follows.
- If Ca > Ct then the waiting function should wake as soon as possible, i.e. Ca+Di+Dm, since the timeout is already satisfied. [_Note:_This specification may result in the total duration of the wait decreasing when measured against a steady clock. —_end note_]
- If Ca <= Ct then the waiting function should not time out until
Clock::now()
returns a time Cn >= Ct, i.e. waking at Ct+Di+Dm. [_Note:_When the clock is adjusted backwards, this specification may result in the total duration of the wait increasing when measured against a steady clock. When the clock is adjusted forwards, this specification may result in the total duration of the wait decreasing when measured against a steady clock. —_end note_]Implementations shall return from such a timeout at any point from the time specified above to the time it would return from a relative timeout on the difference between Ct and the time point of the call to the
_until
function.
30.3.2 Namespace this_thread [thread.thread.this]
Edit paragraph 6, regarding sleep_until
, as follows.
_Effects:_Blocks the calling thread
at least until the timefor the absolute timeout (30.2.4 [thread.req.timing])specified byabs_time
.
Edit paragraph 9, regarding sleep_for
, as follows.
_Effects:_Blocks the calling thread
for at least the timefor the relative timeout (30.2.4 [thread.req.timing])specified byrel_time
.
30.4.2 TimedMutex requirements [thread.timedmutex.requirements]
Edit paragraph 4, regarding try_lock_for
, as follows.
_Effects:_The function attempts to obtain ownership of the mutex within the
timerelative timeout (30.2.4 [thread.req.timing])specified byrel_time
. If the time specified byrel_time
is less than or equal to 0, the function attempts to obtain ownership without blocking (as if by callingtry_lock()
). The function shall return within thetimetimeoutspecified byrel_time
only if it has obtained ownership of the mutex object. [_Note:_As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. —_end note_]
Edit paragraph 10, regarding try_lock_until
, as follows.
_Effects:_The function attempts to obtain ownership of the mutex by the
timeabsolute timeout (30.2.4 [thread.req.timing])specified byabs_time
. Ifabs_time
has already passed, the function attempts to obtain ownership without blocking (as if by callingtry_lock()
). The function shall return before thetimetimeoutspecified byabs_time
only if it has obtained ownership of the mutex object. [_Note:_As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. —_end note_]
30.5.1 Class condition_variable [thread.condition.condvar]
Edit within paragraph 19, regarding wait_until
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,ifexpiration of the absolute timeout (30.2.4 [thread.req.timing]) specified byabs_time <= Clock::now()
abs_time
, or spuriously.- ....
Edit paragraph 21, regarding wait_until
, as follows.
Returns:
cv_status::timeout
ifthe function unblocked becausethe absolute timeout (30.2.4 [thread.req.timing]) specified byabs_time
was reachedabs_time
expired, otherwisecv_status::no_timeout
.
Edit within paragraph 25, regarding wait_for
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,by the elapsed timeexpiration of the relative timeout(30.2.4 [thread.req.timing])specified byrel_time passing
rel_time
, or spuriously.- ....
Edit paragraph 26, regarding wait_for
, as follows.
Returns:
cv_status::timeout
ifthe function unblocked becausethe relative timeout (30.2.4 [thread.req.timing]) specified byrel_time
elapsedrel_time
expired, otherwisecv_status::no_timeout
.
Edit within paragraph 34, regarding the predicate wait_for
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,by the elapsed timeexpiration of the relative timeout(30.2.4 [thread.req.timing])specified byrel_time passing
rel_time
, or spuriously.- ....
- The loop terminates when
pred()
returns true or when thetime durationrelative timeout (30.2.4 [thread.req.timing])specified byrel_time
has elapsed.- ....
30.5.2 Class condition_variable_any [thread.condition.condvarany]
Edit within paragraph 15, regarding wait_until
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,ifexpiration of the absolute timeout (30.2.4 [thread.req.timing]) specified byabs_time <= Clock::now()
abs_time
, or spuriously.- ....
Edit paragraph 17, regarding wait_until
, as follows.
Returns:
cv_status::timeout
ifthe function unblocked becausethe absolute timeout (30.2.4 [thread.req.timing]) specified byabs_time
was reachedabs_time
expired, otherwisecv_status::no_timeout
.
Edit within paragraph 20, regarding wait_for
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,by the elapsed timeexpiration of the relative timeout(30.2.4 [thread.req.timing])specified byrel_time passing
rel_time
, or spuriously.- ....
Edit paragraph 21, regarding wait_for
, as follows.
Returns:
cv_status::timeout
ifthe function unblocked becausethe relative timeout (30.2.4 [thread.req.timing]) specified byrel_time
elapsedrel_time
expired, otherwisecv_status::no_timeout
.
Edit within paragraph 28, regarding the predicate wait_for
, as follows.
Effects:
- ....
- The function will unblock when signaled by a call to
notify_one()
or,a call tonotify_all()
,by the elapsed timeexpiration of the relative timeout(30.2.4 [thread.req.timing])specified byrel_time passing
rel_time
, or spuriously.- ....
- The loop terminates when
pred()
returns true or when thetime durationrelative timeout (30.2.4 [thread.req.timing])specified byrel_time
has elapsed.- ....
30.6.6 Class template future [futures.unique_future]
Edit within paragraph 22, regarding wait_for
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or untilthe relative timeout (30.2.4 [thread.req.timing])specified by
rel_time
haselapsedexpired.
Edit within paragraph 23, regarding wait_for
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thetime periodrelative timeout (30.2.4 [thread.req.timing])specified byrel_time
haselapsedexpired.- ....
Edit within paragraph 25, regarding wait_until
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or until
the current time exceedsthe absolute timeout (30.2.4 [thread.req.timing])specified byabs_time
has expired.
Edit within paragraph 26, regarding wait_until
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thethe time pointabsolute timeout (30.2.4 [thread.req.timing])specified byrel_time
hasbeen reachedexpired.- ....
30.6.7 Class template shared_future [futures.shared_future]
Edit within paragraph 27, regarding wait_for
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or untilthe relative timeout (30.2.4 [thread.req.timing])specified by
rel_time
haselapsedexpired.
Edit within paragraph 28, regarding wait_for
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thetime periodrelative timeout (30.2.4 [thread.req.timing])specified byrel_time
haselapsedexpired.- ....
Edit within paragraph 30, regarding wait_until
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or until
the current time exceedsthe absolute timeout (30.2.4 [thread.req.timing])specified byabs_time
has expired.
Edit within paragraph 31, regarding wait_until
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thethe time pointabsolute timeout (30.2.4 [thread.req.timing])specified byrel_time
hasbeen reachedexpired.- ....
30.6.8 Class template atomic_future [futures.atomic_future]
Edit within paragraph 23, regarding wait_for
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or untilthe relative timeout (30.2.4 [thread.req.timing])specified by
rel_time
haselapsedexpired.
Edit within paragraph 24, regarding wait_for
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thetime periodrelative timeout (30.2.4 [thread.req.timing])specified byrel_time
haselapsedexpired.- ....
Edit within paragraph 27, regarding wait_until
, as follows.
_Effects:_blocks until the associated asynchronous state is ready or until
the current time exceedsthe absolute timeout (30.2.4 [thread.req.timing])specified byabs_time
has expired.
Edit within paragraph 28, regarding wait_until
, as follows.
Returns:
- ....
future_status::timeout
if the function is returning because thethe time pointabsolute timeout (30.2.4 [thread.req.timing])specified byrel_time
hasbeen reachedexpired.- ....