Section: 32.4.5 [thread.thread.this] Status: C++11 Submitter: Switzerland Opened: 2010-08-25 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [thread.thread.this].
View all issues with C++11 status.
Discussion:
Addresses CH-25
Clock related operations are currently not required not to throw. So "Throws: Nothing." is not always true.
[ Resolution proposed by ballot comment: ]
Either require clock related operations not to throw (in 20.10) or change the Throws clauses in 30.3.2. Also possibly add a note that
abs_time
in the past or negativerel_time
is allowed.
[2011-02-10: Howard Hinnant provides a resolution proposal]
[Previous proposed resolution:]
Change the Operational semantics of C1::now()
in 30.3 [time.clock.req],
Table 59 — Clock
requirements as follows:
Table 59 — Clock
requirementsExpression Return type Operational semantics C1::now()
C1::time_point
Returns a time_point
object
representing the current point in time.
Shall not throw an exception.
[2011-02-19: Daniel comments and suggests an alternative wording]
Imposing the no-throw requirement on C1::now()
of any clock time
is an overly radical step: It has the indirect consequences that representation
types for C1::rep
can never by types with dynamic memory managment,
e.g. my big_int
, which are currently fully supported by the time
utilities. Further-on this strong constraint does not even solve the problem
described in the issue, because we are still left with the fact that any
of the arithmetic operations of C1::rep
, C1::duration
,
and C1::time_point
may throw exceptions.
The alternative proposal uses the following strategy: The general Clock
requirements remain untouched, but we require that any functions of the library-provided
clocks from sub-clause 30.7 [time.clock] and their associated types shall not
throw exceptions. Second, we replace existing noexcept
specifications of
functions from Clause 30 that depend on durations, clocks, or time points by wording that
clarifies that these functions can only throw, if the operations of user-provided durations,
clocks, or time points used as arguments to these functions throw exceptions.
[2011-03-23 Daniel and Peter check and simplify the proposed resolution resulting in this paper]
There is an inherent problem with std::time_point
that it doesn't seem to have an equivalent value
for ((time_t)-1)
that gets returned by C's time()
function to signal a problem, e.g., because
the underlying hardware is unavailable. After a lot of thinking and checks we came to the resolution that
timepoint::max()
should be the value to serve as a value signaling errors in cases where we
prefer to stick with no-throw conditions. Of-course, user-provided representation types don't need to
follow this approach if they prefer exceptions to signal such failures.
now()
and from_time_t()
can remain noexcept
with the solution to
return timepoint::max()
in case the current time cannot be determined or (time_t)-1
is passed
in, respectively.
Based on the previous proposed solution to LWG 1487 we decided that the new TrivialClock
requirements
should define that now()
mustn't throw and return timepoint::max()
to signal a problem. That
is in line with the C standard where (time_t)-1
signals a problem. Together with a fix to a - we assumed -
buggy specifcation in 20.11.3 p2 which uses "happens-before" relationship with something that isn't any action:
2 In Table 59
C1
andC2
denote clock types.t1
andt2
are values returned byC1::now()
where the call returningt1
happens before (1.10) the call returningt2
and both of these calls happen beforeC1::time_point::max()
.
[2011-03-23 Review with Concurrency group suggested further simplifications and Howard pointed out, that we do not need time_point::max() as a special value.]
also the second "happens before" will be changed to "occurs before" in the english meaning. this is to allow a steady clock to wrap.
Peter updates issue accordingly to discussion.[Note to the editor: we recommend removal of the following redundant paragraphs in 32.7.5 [thread.condition.condvarany] p. 18 to p. 21, p. 27, p. 28, p. 30, and p. 31 that are defining details for the wait functions that are given by the Effects element. ]
[Note to the editor: we recommend removal of the following redundant paragraphs in
32.7.4 [thread.condition.condvar]: p24-p26, p33-p34, and p36-p37 that are defining details for the
wait_for
functions. We believe these paragraphs are redundant with respect to the Effects clauses that
define semantics based on wait_until
. An example of such a specification is the wait()
with a predicate.
]
Proposed resolution:
Change p2 in 20.11.3 [time.clock.req] as follows
2 In Table 59
C1
andC2
denote clock types.t1
andt2
are values returned byC1::now()
where the call returningt1
happens before (1.10) the call returningt2
and both of these callshappenoccur beforeC1::time_point::max()
. [ Note: This meansC1
didn't wrap around betweent1
andt2
— end note ]
Add the following new requirement set at the end of sub-clause 30.3 [time.clock.req]: [Comment:
This requirement set is intentionally incomplete. The reason for
this incompleteness is the based on the fact, that if we would make it right for C++0x, we would end up defining
something like a complete ArithmeticLike
concept for TC::rep
, TC::duration
, and TC::time_point
.
But this looks out-of scope for C++0x to me. The effect is that we essentially do not exactly say, which arithmetic
or comparison operations can be used in the time-dependent functions from Clause 30, even though I expect that
all declared functions of duration
and time_point
are well-formed and well-defined. — end comment]
3 [ Note: the relative difference in durations between those reported by a given clock and the SI definition is a measure of the quality of implementation. — end note ]
? A type
TC
meets theTrivialClock
requirements if:
TC
satisfies theClock
requirements (30.3 [time.clock.req]),the types
TC::rep
,TC::duration
, andTC::time_point
satisfy the requirements ofEqualityComparable
( [equalitycomparable]),LessThanComparable
( [lessthancomparable]),DefaultConstructible
( [defaultconstructible]),CopyConstructible
( [copyconstructible]),CopyAssignable
( [copyassignable]),Destructible
( [destructible]), and of numeric types ([numeric.requirements]) [Note: This means in particular, that operations of these types will not throw exceptions — end note ],lvalues of the types
TC::rep
,TC::duration
, andTC::time_point
are swappable (16.4.4.3 [swappable.requirements]),the function
TC::now()
does not throw exceptions, andthe type
TC::time_point::clock
meets theTrivialClock
requirements, recursively.
Modify 30.7 [time.clock] p. 1 as follows:
1 - The types defined in this subclause shall satisfy the
TrivialClock
requirements (20.11.1).
Modify 30.7.2 [time.clock.system] p. 1, class system_clock
synopsis, as follows:
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 is_steady = unspecified; static time_point now() noexcept; // Map to C API static time_t to_time_t (const time_point& t) noexcept; static time_point from_time_t(time_t t) noexcept; };
Modify the prototype declarations in 30.7.2 [time.clock.system] p. 3 + p. 4 as indicated (This
edit also fixes the miss of the static
specifier in these prototype declarations):
static time_t to_time_t(const time_point& t) noexcept;static time_point from_time_t(time_t t) noexcept;
Modify 30.7.7 [time.clock.steady] p. 1, class steady_clock
synopsis, as follows:
class steady_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified > period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified, duration> time_point; static const bool is_monotonic is_steady = true; static time_point now() noexcept; };
Modify 30.7.8 [time.clock.hires] p. 1, class high_resolution_clock
synopsis, as follows:
class high_resolution_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified > period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified, duration> time_point; static const bool is_monotonic is_steady = unspecified; static time_point now() noexcept; };
Add a new paragraph at the end of 32.2.4 [thread.req.timing]:
6 The resolution of timing provided by an implementation depends on both operating system and hardware. The finest resolution provided by an implementation is called the native resolution.
? Implementation-provided clocks that are used for these functions shall meet the
TrivialClock
requirements (30.3 [time.clock.req]).
Edit the synopsis of 32.4.5 [thread.thread.this] before p. 1. [Note: this duplicates edits also in D/N3267]:
template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time)noexcept;
Modify the prototype specifications in 32.4.5 [thread.thread.this] before p. 4 and p. 6 and re-add a Throws element following the Synchronization elements at p. 5 and p. 7:
template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept;4 - [...]
5 - Synchronization: None. ? - Throws: Nothing ifClock
satisfies theTrivialClock
requirements (30.3 [time.clock.req]) and operations ofDuration
do not throw exceptions. [Note: Instantiations of time point types and clocks supplied by the implementation as specified in 30.7 [time.clock] do not throw exceptions. — end note]
template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time)noexcept;6 [...]
7 Synchronization: None. ? Throws: Nothing if operations ofchrono::duration<Rep, Period>
do not throw exceptions. [Note: Instantiations of duration types supplied by the implementation as specified in 30.7 [time.clock] do not throw exceptions. — end note]
Fix a minor incorrectness in p. 5: Duration types need to compare against duration<>::zero()
,
not 0
:
3 The expression
[...] 5 Effects: The function attempts to obtain ownership of the mutex within the relative timeout (30.2.4) specified bym.try_lock_for(rel_time)
shall be well-formed and have the following semantics:rel_time
. If the time specified byrel_time
is less than or equal to0
rel_time.zero()
, the function attempts to obtain ownership without blocking (as if by callingtry_lock()
). The function shall return within the timeout specified 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 ]
Modify the class timed_mutex
synopsis in 32.6.4.3.2 [thread.timedmutex.class] as indicated:
[Note: this duplicates edits also in D/N3267]:
class timed_mutex { public: [...] template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)noexcept; template <class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; [...] };
Modify the class recursive_timed_mutex
synopsis in 32.6.4.3.3 [thread.timedmutex.recursive] as indicated:
[Note: this duplicates edits also in D/N3267]:
class recursive_timed_mutex { public: [...] template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)noexcept; template <class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; [...] };
Modify the class template unique_lock
synopsis in 32.6.5.4 [thread.lock.unique] as indicated.
[Note: this duplicates edits also in D/N3267]:
template <class Mutex> class unique_lock { public: [...] template <class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time)noexcept; template <class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time)noexcept; [...] };
Modify the constructor prototypes in 32.6.5.4.2 [thread.lock.unique.cons] before p. 14 and p. 17 [Note: this duplicates edits also in D/N3267]:
template <class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time)noexcept;
template <class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time)noexcept;