Nov 30, 2021
bsl::chrono Integration with bsl and bdl¶
Overview¶
In BDE 3.86 support for bsl::chrono::duration and bsl::chrono::time_point was added to bslmt and bdlmt. This enables users who prefer using bsl::chrono::duration and bsl::chrono::time_point to better integrate with the BDE libraries. Specifically, conversions between bsl::chrono::duration and bsls::TimeInterval were added, and support for bsl::chrono::time_point was added to the synchronization primitives in bslmt, as well as the classes bslmt::ThreadUtil, bdlmt::EventScheduler, and bdlmt::Throttle.
bsl::chrono::duration and bsls::TimeInterval¶
The BDE types bsls::TimeInterval and bsl::chrono::duration are both representations of a time interval, but bsls::TimeInterval is a concrete type (representing an interval in seconds and nanoseconds), while bsl::chrono::duration is a template whose representation, precision, and range are determined by its template parameters. BDE now provides a set of operations to convert between bsls::TimeInterval and bsl::chrono::duration. These include:
conversion from bsl::chrono::duration to bsls::TimeInterval,
bsls::TimeInterval::addDuration - adds a bsl::chrono::duration to this interval, and
bsls::TimeInterval::asDuration - returns this interval as a bsl::chrono::duration.
Restrictions:
the behavior is undefined if the value being converted is outside of the representatable range of the result type, and
no conversions where the storage type is a floating point value are provided (use a
duration_cast
to cast to an integral representation, or bslmt::ChronoUtil::durationToTimeInterval),the conversion from bsl::chrono::duration to bsls::TimeInterval is explicit when the conversion is potentially lossy.
For example, to create a bsls::TimeInterval interval, add a second, and then convert the bsls::TimeInterval interval to a duration holding an integer of seconds:
bsls::TimeInterval interval;
interval.addDuration(bsl::chrono::seconds(1));
bsl::chrono::seconds duration = interval.asDuration<bsl::chrono::seconds>();
Potentially Lossy Conversions¶
The conversion from bsl::chrono::duration to bsls::TimeInterval is implicit if the conversion can be done without loss of precision, whereas it must be explicit if the conversion is potentially lossy. For example, if we define a duration in picoseconds, this requires a potentially lossy conversion when converted to a bsls::TimeInterval (defined in terms of nanoseconds). Hence, the following code does not compile (the attempted conversion would require use of the implicit bsls::TimeInterval user-defined conversion):
typedef bsl::chrono::duration<unsigned long long, bsl::ratio<1, 1000000000000> > Picoseconds;
Picoseconds d(5001);
bsls::TimeInterval ti = d; // does not compile: implicit conversion unavailable
The following example will compile because the conversion to bsls::TimeInterval is explicit:
Picoseconds d(5001);
bsls::TimeInterval ti = bsls::TimeInterval(d); // does compile: initial explicit conversion
In contrast, a duration defined in milliseconds can be converted to a bsls::TimeInterval without a loss of precision, so the following example will compile:
bsl::chrono::milliseconds d(5001); // does compile (non-lossy conversion)
bsls::TimeInterval ti = d;
Note that just because a bsl::chrono::duration type can be converted to a bsls::TimeInterval without loss of precision (meaning an implicit conversion is available) does not guarantee that the value for that bsl::chrono::duration is in the range that can be represented by bsls::TimeInterval.
Note
Converting a bsl::chrono::duration value that is outside of the representable range of bsls::TimeInterval results in undefined behavior (see bsls::TimeInterval::isValid).
Using bsls::TimeInterval with Literals¶
A set of user-defined literals (UDL) has been provided to form bsl::chrono::duration objects with various duration periods such as hours, minutes, seconds, milliseconds, microseconds and nanoseconds. The ud-suffixes are preceded with the ‘_’ symbol to distinguish between the bsl::chrono UDLs and the std::chrono UDLs introduced in the C++14 standard and implemented in the standard library.
using namespace bsl::chrono_literals;
bsls::TimeInterval elapsedTime = 5_s;
Using bsls::TimeInterval with Helper Types¶
The standard helper types for time units are available in the bsl namespace.
bsls::TimeInterval elapsedTime(bsl::chrono::microseconds(500));
bsl::chrono::microseconds duration = elapsedTime.asDuration<bsl::chrono::microseconds>();
bsls::SystemClockType versus bsl::chrono Clocks¶
On all production (and tested) platforms, bsls::SystemClockType::e_REALTIME is equivalent to std::chrono::system_clock and bsls::SystemClockType::e_MONOTONIC is equivalent to std::chrono::steady_clock (meaning the BDE clock-type and the matching standard library clock can be used interchangeably). If a platform is found where this is not the case, bsl::chrono::system_clock and bsl::chrono::steady_clock will be modified to match the ones indicated by bsls::SystemClockType. As such, we strongly recommend using bsl::chrono when working with BDE types.
bslmt::ChronoUtil¶
This struct provides a namespace for utility functions that operate on bsl::chrono facilities. Presently, it contains four methods:
bslmt::ChronoUtil::timedWait with an additional argument.
The method bslmt::ChronoUtil::durationToTimeInterval returns a
bsls::TimeInterval for the provided duration, and allows durations with
floating-point representations. The method
bslmt::ChronoUtil::isMatchingClock returns true if the specified (template
parameter) clock matches the clock indicated by a bsls::SystemClockType
value. The two bslmt::ChronoUtil::timedWait methods are helpers for
implementing higher-level timedWait
operations (e.g.,
bslmt::TimedSemaphore::timedWait) using the logic explained in
Enhancements to bslmt Components to Support bsl::chrono.
Converting a Floating Point bsl::chrono::duration¶
The method bslmt::ChronoUtil::durationToTimeInterval make a best effort conversion to a bsls::TimeInterval from any bsl::chrono::duration.
bsls::TimeInterval fp = bslmt::ChronoUtil::durationToTimeInterval(
bsl::chrono::duration<double>(6.5));
Enhancements to bslmt Components to Support bsl::chrono¶
The classes in bslmt that accept a bsls::SystemClockType in their
constructor were augmented to accept bsl::chrono::system_clock and
bsl::chrono::steady_clock (user defined clocks are not accepted in the
constructor). Additionally, the timeWait
methods were augmented to accept a
bsl::chrono::time_point, with an arbitrary clock.
Note
It is strongly recommended to supply bsl::chrono::time_point objects that
use the same clock as the one used to construct the bslmt
object.
If the clock of the bsl::chrono::time_point does not match the clock
provided to the
constructor, the timed-wait method must make an addition comparison against
time_point::clock::now()
(and potentially, do this repeatedly) to ensure
the contract of the
method is guaranteed (the function does not time out before the specified
bsl::chrono::time_point has occurred). If the clock of the bsl::chrono::time_point
matches the clock provided to the constructor, the timed-wait method does not
need an additional comparison against time_point::clock::now()
(potentially
multiple comparisons) and hence is more efficient.
The following classes were augmented:
bslmt::Sluice, and
For example, to use a bsl::chrono::time_point with bslmt::Condition:
using namespace bsl::chrono_literals;
// Using the same clock as the time_points supplied to timedWait is
// highly recommended.
bslmt::Condition condition((bsl::chrono::steady_clock()));
bslmt::Mutex mutex;
int rc = condition.timedWait(&mutex, bsl::chrono::steady_clock::now() + 5_s);
if (0 == rc) {
// condition signalled, do something
}
else if (bslmt::Condition::e_TIMED_OUT == rc) {
// timeout
}
else {
// error
}
Miscelaneous Interface Enhancements¶
bdlmt::EventScheduler¶
The class bdlmt::EventScheduler was augmented similarly to bslmt, but
instead of timed-wait methods being added, all the scheduling and rescheduling
methods were augmented to accept a bsl::chrono::time_point. Overloads
accepting a time_point
were added to the following methods:
bslmt::ThreadUtil¶
The following methods were added:
bdlmt::Throttle¶
The class bdlmt::Throttle had its initialization methods augmented to accept bsl::chrono::system_clock and bsl::chrono::steady_clock:
No other changes were made (please see this component’s documentation for an explanation).