...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Boost.Chrono is in the latest Boost release
in the folder /boost/chrono
.
Documentation, tests and examples folder are at boost/libs/chrono/
.
You can also access the latest (unstable?) state from the Boost trunk directories boost/chrono and libs/chrono. Just go to here and follow the instructions there for anonymous SVN access.
The simple way is to decompress (or checkout from SVN) the files in your BOOST_ROOT directory.
Boost.Chrono can be configured as a header-only
library defining BOOST_CHRONO_HEADER_ONLY
. However
Boost.Chrono depends on the non header-only library Boost.System, so that
you will need to link with boost_system.
Boost.System has an undocumented feature (use of macro BOOST_ERROR_CODE_HEADER_ONLY) to make it header only.
If BOOST_CHRONO_HEADER_ONLY
is not
defined you need to compile it and build the library before use, for example
using:
bjam libs/chrono/build
In particular, Boost.Chrono depends on:
for configuration purposes, ...
for throw_exception, ...
for cstdint conformance, ...
for MPL Assert and bool, logical ...
for operators, ...
for ratio, milli, micro, ...
for error_code, ...
for is_base, is_convertible, common_type, ...
for enable_if, ...
In addition to link with the Boost.Chrono library you need also to link with the Boost.System library. If Boost.System is configured defining BOOST_ERROR_CODE_HEADER_ONLY you will no need to link with it as the dependent part is header only then.
All functions in the library are exception-neutral and provide strong guarantee of exception safety as long as the underlying parameters provide it.
All functions in the library are thread-unsafe except when noted explicitly.
As Boost.Chrono doesn't use mutable global variables the thread-safety analysis is limited to the access to each instance variable. It is not thread safe to use a function that modifies the access to a user variable if another can be reading or writing it.
The implementation will eventually work with most C++03 conforming compilers. Currently I use to test with on:
Windows with
MinGW with
Ubuntu with * GCC 4.4.6 * GCC 4.4.6 -std=c++0x * GCC 4.5.4 * GCC 4.5.4 -std=c++0x * GCC 4.6.1 * GCC 4.6.1 -std=c++0x * Intel 12.1.3 * Intel 12.1.3 -std=c++0x
OsX with
The committed code is tested with much more compilers. There are two compilers (VACPP and Borland) that don't provide the needed features. Other as Intel and Sun have some issues with i/o. While everything compiles and link correctly, there are some runtime issues I have not cached yet. See the regression tests for details.
Note | |
---|---|
Please let us know how this works on other platforms/compilers. |
Note | |
---|---|
Please send any questions, comments and bug reports to boost <at> lists <dot> boost <dot> org. |
duration
and How Do I Use One?m3 + us3
to minutes
Instead of
microseconds
?duration
Parameter?duration
to a function with the
units being ambiguous?
The duration
is the heart of this
library. The interface that the user will see in everyday use is nearly
identical to that of Boost.DateTime time
duration
s authored by Jeff Garland,
both in syntax and in behavior. This has been a very popular boost library
for 7 years. There is an enormous positive history with this interface.
The library consists of six units of time duration
:
These units were chosen as a subset of the boost library because they are
the most common units used when sleeping, waiting on a condition variable,
or waiting to obtain the lock on a mutex. Each of these units is nothing
but a thin wrapper around a signed integral count. That is, when you construct
minutes
(3)
, all that
happens is a 3
is stored inside
minutes
. When you construct
microseconds
(3)
, all that
happens is a 3
is stored inside
microseconds
.
The only context in which these different types differ is when being converted
to one another. At this time, unit-specific compile-time conversion constants
are used to convert the source unit to the target unit. Only conversions
from coarser units to finer units are allowed (in Boost). This restriction
ensures that all conversions are always exact. That is, microseconds
can always represent
any value minutes
has.
In Boost.DateTime, these units are united
via inheritance. Boost.Chrono instead
unites these units through the class template duration
. That is, in Boost.Chrono all six of the above units are nothing
but typedefs to different instantiations of duration
. This change from Boost.DateTime
has a far reaching positive impact, while not changing the syntax of the
everyday use at all.
The most immediate positive impact is that the library can immediately
generate any unit, with any precision it needs. This is sometimes necessary
when doing comparisons or arithmetic between duration
s of differing precision,
assuming one wants the comparison and arithmetic to be exact.
A secondary benefit is that by publishing the class template duration
interface, user code
can very easily create duration
s with any precision they
desire. The ratio
utility
is used to specify the precision, so as long as the precision can be expressed
by a rational constant with respect to seconds, this framework can exactly
represent it (one third of a second is no problem, and neither is one third
of a femto
second). All
of this utility and flexibility comes at no cost just by making use of
the no-run-time-overhead ratio
facility.
In Boost.DateTime, hours
does not have the same representation
as nanoseconds
. The former is usually
represented with a long
whereas
a long long
is required for the latter. The reason for this is simply range. You don't
need many hours to cover an extremely large range of time. But this isn't
true of nanoseconds. Being able to reduce the sizeof overhead for some
units when possible, can be a significant performance advantage.
Boost.Chrono continues, and generalizes
that philosophy. Not only can one specify the precision of a duration
, one can also specify
its representation. This can be any integral type, or even a floating-point
type. Or it can be a user-defined type which emulates an arithmetic type.
The six predefined units all use signed integral types as their representation.
And they all have a minimum range of ± 292 years. nanoseconds
needs 64 bits to cover
that range. hours
needs only 23 bits to cover
that range.
A duration
has a representation
and a tick period (precision).
template <class Rep, class Period = ratio
<1> > class duration;
The representation is simply any arithmetic type, or an emulation of
such a type. The representation stores a count of ticks. This count is
the only data member stored in a duration
. If the representation
is floating-point, it can store fractions of a tick to the precision
of the representation. The tick period is represented by a ratio
and is encoded into the duration
's type, instead of
stored. The tick period only has an impact on the behavior of the duration
when a conversion between
different duration
s is attempted. The
tick period is completely ignored when simply doing arithmetic among
like duration
s.
Example:
typedef boost::chrono::duration
<long, boost::ratio<60> > minutes; minutes m1(3); // m1 stores 3 minutes m2(2); // m2 stores 2 minutes m3 = m1 + m2; // m3 stores 5 typedef boost::chrono::duration
<long long, boost::micro> microseconds; microseconds us1(3); // us1 stores 3 microseconds us2(2); // us2 stores 2 microseconds us3 = us1 + us2; // us3 stores 5 microseconds us4 = m3 + us3; // us4 stores 300000005
In the final line of code above, there is an implicit conversion from minutes to microseconds, resulting in a relatively large number of microseconds.
If you need to access the tick count within a duration
, there is a member
count()
which simply returns the stored tick count.
long long tc = us4.count(); // tc is 300000005
These duration
's have very simple,
very predictable, and very observable behavior. After all, this is really
nothing but the time-tested interface of Jeff's boost time duration
library (unified with
templates instead of inheritance).
minutes m4 = m3 + us3;
It won't compile! The rationale is that implicit truncation error should
not be allowed to happen. If this were to compile, then m4
would hold 5
,
the same value as m3
.
The value associated with us3
has been effectively ignored. This is similar to the problem of assigning
a double to an int
: the
fractional part gets silently discarded.
There is a duration_cast
facility to explicitly
ask for this behavior:
minutes m4 = boost::chrono::duration_cast
<minutes>(m3 + us3); // m4.count() == 5
In general, one can perform duration
arithmetic at will.
If duration_cast
isn't used, and
it compiles, the arithmetic is exact. If one wants to override this exact
arithmetic behavior, duration_cast
can be used to
explicitly specify that desire. The duration_cast
has the same efficiency
as the implicit conversion, and will even be exact as often as it can.
You can use duration_cast
<>
to convert the duration
into whatever units
you desire. This facility will round down (truncate) if an exact conversion
is not possible. For example:
boost::chrono::nanoseconds
start; boost::chrono::nanoseconds
end; typedef boost::chrono::milliseconds
ms; ms d = boost::chrono::duration_cast
<ms>(end - start); // d now holds the number of milliseconds from start to end. std::cout << ms.count() << "ms\n";
We can convert to nanoseconds
, or some integral-based
duration which nanoseconds
will always exactly
convert to, then duration_cast
<>
is unnecessary:
typedef boost::chrono::nanoseconds
ns;
ns d = end - start;
std::cout << ns.count() << "ns\n";
If you need seconds with a floating-point representation you can also
eliminate the duration_cast
<>
:
typedef boost::chrono::duration
<double> sec; // seconds, stored with a double
sec d = end - start;
std::cout << sec.count() << "s\n";
If you're not sure if you need duration_cast
<>
or not, feel free to try it without. If the conversion is exact, or if
the destination has a floating-point representation, it will compile:
else it will not compile.
If you need to use duration_cast
<>
,
but want to round up, instead of down when the conversion is inexact,
here is a handy little helper function to do so. Writing it is actually
a good starter project for understanding Boost.Chrono:
template <classToDuration
, class Rep, class Period> ToDuration round_up(boost::chrono::duration
<Rep, Period> d) { // first round down ToDuration result = boost::chrono::duration_cast
<ToDuration>(d); if (result < d) // comparisons are *always* exact ++result; // increment by one tick period return result; } typedef boost::chrono::milliseconds
ms; ms d = round_up<ms>(end - start); // d now holds the number of milliseconds from start to end, rounded up. std::cout << ms.count() << "ms\n";
Boost.Chrono provides few simple rounding utility functions for working with durations.
// round down template <classTo
, class Rep, class Period> To floor(const duration<Rep, Period>& d) { return duration_cast<To>(d); } // round to nearest, to even on tie template <classTo
, class Rep, class Period> To round(const duration<Rep, Period>& d) { To t0 = duration_cast<To>(d); To t1 = t0; ++t1; BOOST_AUTO(diff0, d - t0); BOOST_AUTO(diff1, t1 - d); if (diff0 == diff1) { if (t0.count() & 1) return t1; return t0; } else if (diff0 < diff1) return t0; return t1; } // round up template <classTo
, class Rep, class Period> To ceil(const duration<Rep, Period>& d) { To t = duration_cast<To>(d); if (t < d) ++t; return t; }
The beauty of the chrono library is the ease and accuracy with which
such conversions can be made. For example to convert from milliseconds
(1/1000
of a second), to 1/30
of a second, one must multiply the milliseconds
by 0.03
. It is common knowledge
that you can't exactly represent 0.03
in a computer. Nevertheless round will exactly (with no round off error)
detect a tie and round to even when this happens. The differences diff0
and diff1
are not approximate, but exact differences, even when d
has the units of millisecond and To
is 1/30
of a second. The unit of diff0
and diff1
is 1/3000
of a second which both millisecond
and 1/30
of a second exactly convert to (with
no truncation error).
Similarly, the comparison t
< d
in ceil
is exact, even when there is no exact conversion between t
and d
.
Example use of rounding functions
#include <iostream> #include <boost/chrono/chrono_io.hpp> #include <boost/chrono/floor.hpp> #include <boost/chrono/round.hpp> #include <boost/chrono/ceil.hpp> int main() { using namespace boost::chrono; milliseconds ms(2500); std::cout << floor<seconds>(ms) << '\n'; std::cout << round<seconds>(ms) << '\n'; std::cout << ceil<seconds>(ms) << '\n'; ms = milliseconds(2516); typedef duration<long, boost::ratio<1, 30> > frame_rate; std::cout << floor<frame_rate>(ms) << '\n'; std::cout << round<frame_rate>(ms) << '\n'; std::cout << ceil<frame_rate>(ms) << '\n'; return 0; }
The output of this program should be
2 seconds 2 seconds 3 seconds 75 [1/30]seconds 75 [1/30]seconds 76 [1/30]seconds
I don't want to deal with writing duration_cast
all over the place. I'm content with the precision of my floating-point
representation.
Not a problem. When the destination of a conversion has floating-point representation, all conversions are allowed to happen implicitly.
typedef boost::chrono::duration
<double,ratio
<60> > dminutes; dminutes dm4 = m3 + us3; // dm4.count() == 5.000000083333333
If you were writing these conversions by hand, you could not make it
more efficient. The use of ratio
ensures that all conversion constants are simplified as much as possible
at compile-time. This usually results in the numerator or denominator
of the conversion factor simplifying to 1
,
and being subsequently ignored in converting the run-time values of the
tick counts.
There are several options open to the user:
void f(boost::chrono::duration<double> d) // accept floating-point seconds { // d.count() == 3.e-6 when passed boost::chrono::microseconds(3) } f(boost::chrono::microseconds(3));
duration
s, and is content
with handling nothing finer than say nanoseconds (just as an example),
he can simply specify nanoseconds as the parameter:
void f(boost::chrono::nanoseconds d) { // d.count() == 3000 when passed boost::chrono::microseconds(3) } f(boost::chrono::microseconds(3));
In this design, if the client wants to pass in a floating-point duration
, or a duration
of finer precision
than nanoseconds, then the client is responsible for choosing his own
rounding mode in the conversion to nanoseconds.
boost::chrono::duration
<double> s(1./3); // 1/3 of a second
f(boost::chrono::duration_cast<boost::chrono::nanoseconds>(s)); // round towards zero in conversion to nanoseconds
In the example above, the client of f has chosen "round towards
zero" as the desired rounding mode to nanoseconds. If the client
has a duration
that won't exactly
convert to nanoseconds, and fails to choose how the conversion will take
place, the compiler will refuse the call:
f(s); // does not compile
duration
, but wants to work
with integral representations and wants to control the rounding mode
internally, then he can template the function:
template <class Rep, class Period> void f(boost::chrono::duration
<Rep, Period> d) { // convert d to nanoseconds, rounding up if it is not an exact conversion boost::chrono::nanoseconds ns = boost::chrono::duration_cast<boost::chrono::nanoseconds>(d); if (ns < d) ++ns; // ns.count() == 333333334 when passed 1/3 of a floating-point second } f(boost::chrono::duration
<double>(1./3));
duration
s, he can enforce
that behavior like so:
template <class Period> void f(boost::chrono::duration
<long long, Period> d) { // convert d to nanoseconds, rounding up if it is not an exact conversion boost::chrono::nanoseconds ns = boost::chrono::duration_cast<nanoseconds>(d); if (ns < d) ++ns; // ns.count() == 333333334 when passed 333333333333 picoseconds } // About 1/3 of a second worth of picoseconds f(boost::chrono::duration
<long long, boost::pico>(333333333333));
Clients with floating-point duration
s who want to use f
will now have to convert to an integral duration
themselves before passing
the result to f.
In summary, the author of f has quite a bit of flexibility and control
in the interface he wants to provide his clients with, and easy options
for manipulating that duration
internal to his function.
duration
to a function with the
units being ambiguous?
No. No matter which option the author of f
chooses above, the following client code will not compile:
f(3); // Will not compile, 3 is not implicitly convertible to any __duration
This depend on the representation. The default typedefs uses a representation that don't handle overflows. The user can define his own representation that manage overflow as required by its application.
While duration
s only have precision
and representation to concern themselves, clocks and time_point
s are intimately related
and refer to one another. Because clocks are simpler to explain, we will
do so first without fully explaining time_point
s. Once clocks are introduced,
it will be easier to then fill in what a time_point
is.
A clock is a concept which bundles 3 things:
duration
type.
time_point
type.
time_point
.
The standard defines three system-wide clocks that are associated to the computer time.
system_clock
represents system-wide
realtime clock that can be synchronized with an external clock.
steady_clock
can not be changed
explicitly and the time since the initial epoch increase in a steady
way.
high_resolution_clock
intend
to use the system-wide clock provided by the platform with the highest
resolution.
Boost.Chrono provides them when supported by the underlying platform. A given platform may not be able to supply all three of these clocks.
The library adds some clocks that are specific to a process or a thread, that is there is a clock per process or per thread.
The user is also able to easily create more clocks.
Given a clock named Clock, it will have:
class Clock { public: typedef an arithmetic-like type rep; typedef an instantiation of ratio period; typedef boost::chrono::duration
<rep, period>duration
; typedef boost::chrono::time_point
<Clock
> time_point; static constexpr bool is_steady = true or false; static time_point now(); };
One can get the current time from Clock with:
Clock::time_point t1 = Clock::now();
And one can get the time duration
between two time_point
s associated with Clock
with:
Clock::duration d = Clock::now() - t1;
And one can specify a past or future time_point
with:
Clock::time_point t2 = Clock::now() + d;
Note how even if a particular clock becomes obsolete, the next clock in
line will have the same API. There is no new learning curve to come up.
The only source code changes will be simply changing the type of the clock.
The same duration
and time_point
framework continues
to work as new clocks are introduced. And multiple clocks are safely and
easily handled within the same program.
A time_point
represents a point
in time, as opposed to a duration
of time. Another way
of saying the same thing, is that a time_point
represents an epoch
plus or minus a duration
. Examples of time_point
s include:
In each of the examples above, a different epoch is implied. Sometimes
an epoch has meaning for several millennia. Other times the meaning of
an epoch is lost after a while (such as the start of a timer, or when the
computer booted). However, if two time_point
s are known to share
the same epoch, they can be subtracted, yielding a valid duration
, even if the definition
of the epoch no longer has meaning.
In Boost.Chrono, an epoch is a purely
abstract and unspecified concept. There is no type representing an epoch.
It is simply an idea that relates (or doesn't) time_point
s to a clock, and in
the case that they share a clock, time_point
s to one another. time_point
s associated with different
clocks are generally not interoperable unless the relationship between
the epochs associated with each clock is known.
A time_point
has a clock and a
duration
.
template <classClock
, classDuration
= typename Clock::duration> classtime_point
;
The time_point
's clock is not stored.
It is simply embedded into the time_point
's type and serves
two purposes:
time_point
s originating
from different clocks have different types, the compiler can be instructed
to fail if incompatible time_point
s are used in
inappropriate ways.
time_point
, one often needs
to compare that time_point
to "now".
This is very simple as long as the time_point
knows what clock
it is defined with respect to.
A time_point
's duration
is stored as the only
data member of the time_point
. Thus time_point
s and their corresponding
duration
have exactly the same
layout. But they have very different meanings. For example, it is one
thing to say I want to sleep for 3 minutes. It is a completely different
thing to say I want to sleep until 3 minutes past the time I started
that timer (unless you just happened to start that timer now). Both meanings
(and options for sleeping) have great practical value in common use cases
for sleeping, waiting on a condition variable, and waiting for a mutex's
lock. These same concepts and tools are found (for example) in Ada.
A timer example:
void f()
{
boost::chrono::steady_clock::time_point start = boost::chrono::steady_clock::now();
g();
h();
duration
<double> sec = boost::chrono::steady_clock::now() - start;
cout << "f() took " << sec.count() << " seconds\n";
}
Note that if one is using the duration
between two clock
time_point
s in a way where the
precision of the duration
matters, it is good
practice to convert the clock's duration
to a known duration
. This insulates the
code from future changes which may be made to the clock's precision in
the future. For example steady_clock
could easily be
based on the clock speed of the cpu. When you upgrade to a faster machine,
you do not want your code that assumed a certain tick period of this
clock to start experiencing run-time failures because your timing code
has silently changed meaning.
A delay loop example:
// delay for at least 500 nanoseconds: auto go = boost::chrono::steady_clock::now() + boost::chrono::nanoseconds(500); while (boost::chrono::steady_clock::now() < go) ;
The above code will delay as close as possible to half a microsecond,
no matter what the precision of steady_clock
is. The more precise
steady_clock
becomes, the more
accurate will be the delay to 500 nanoseconds.
system_clock
is useful when
you need to correlate the time with a known epoch so you can convert
it to a calendar time. Note the specific functions in the system_clock
class.
steady_clock
is useful when
you need to wait for a specific amount of time. steady_clock
time can not be
reset. As other steady clocks, it is usually based on the processor tick.
Here is a polling solution, but it will probably be too inefficient:
boost::chrono::steady_clock
::time_point start= chrono::steady_clock
::now(); boost::chrono::steady_clock
::duration delay= chrono::seconds(5); while (boost::chrono::steady_clock
::now() - start <= delay) {}
When available, high_resolution_clock
is usually
more expensive than the other system-wide clocks, so they are used only
when the provided resolution is required to the application.
Process and thread clocks are used usually to measure the time spent by code blocks, as a basic time-spent profiling of different blocks of code (Boost.Chrono.Stopwatch is a clear example of this use).
You can use thread_clock
whenever you want
to measure the time spent by the current thread. For example:
boost::chrono::thread_clock
::time_point start=boost::chrono::thread_clock
::now(); // ... do something ... typedef boost::chrono::milliseconds
ms; ms d = boost::chrono::thread_clock
::now() - start; // d now holds the number of milliseconds from start to end. std::cout << ms.count() << "ms\n";
If you need seconds with a floating-point representation you can do:
typedef boost::chrono::duration
<double> sec; // seconds, stored with a double.
sec d = end - start;
std::cout << sec.count() << "s\n";
If you would like to programmatically inspect
, you can get the representation
type with thread_clock
::duration
, and the tick period with thread_clock
::rep
(which should be a type thread_clock
::periodratio
which has nested values
and ratio
::num
).
The tick period of ratio
::denthread_clock
is
seconds: thread_clock
::period::num / thread_clock
::period::den1/1000000000
in this case (1
billionth
of a second), stored in a long
long
.
Any duration
can be streamed out
to a basic_ostream
. The
run-time value of the duration
is formatted according
to the rules and current format settings for duration
::rep
get_duration_style and the durationpunct
facet.
the format is either
<value> <unit>
or
<unit> <value>
Warning | |
---|---|
Need to be changed This is followed by a single space and then the
compile-time unit name of the
|
Example:
#include <iostream> #include <boost/chrono/chrono_io.hpp> int main() { using namespace std; using namespace boost; cout << "milliseconds(1) = " << boost::chrono::milliseconds(1) << '\n'; cout << "milliseconds(3) + microseconds(10) = " << boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n'; cout << "hours(3) + minutes(10) = " << boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n'; typedef boost::chrono::duration<long long, boost::ratio<1, 2500000000> > ClockTick; cout << "ClockTick(3) + boost::chrono::nanoseconds(10) = " << ClockTick(3) + boost::chrono::nanoseconds(10) << '\n'; // ... return 0; }
The output could be
milliseconds(1) = 1 microsecond milliseconds(3) + microseconds(10) = 3010 microseconds hours(3) + minutes(10) = 190 minutes ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]seconds Set cout to use short names: milliseconds(3) + microseconds(10) = 3010 μs hours(3) + minutes(10) = 190 m ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]s system_clock::now() = 129387415616250000 [1/10000000]s since Jan 1, 1970 monotonic_clock::now() = 37297387636417 ns since boot Set cout to use long names: high_resolution_clock::now() = 37297387655134 nanoseconds since boot
As can be seen, each duration type can be streamed without having to
manually stream the compile-time units after the run-time value. And
when the compile-time unit is known to be a "common unit",
English names are used. For "uncommon units" a unit name is
composed from the reduced numerator and denominator of the associated
ratio
. Whatever stream/locale
settings are set for duration::rep
are used for the value. Additionally, when the value is 1, singular forms
for the units are used.
Sometimes it is desired to shorten these names by using the SI symbols
instead of SI prefixes. This can be accomplished with the use of the
symbol_format
manipulator [1]:
cout << "\nSet cout to use short names:\n"; cout << boost::chrono::symbol_format; cout << "milliseconds(3) + microseconds(10) = " << boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n'; cout << "hours(3) + minutes(10) = " << boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n'; cout << "ClockTick(3) + nanoseconds(10) = " << ClockTick(3) + boost::chrono::nanoseconds(10) << '\n';
The output could be
Set cout to use short names: milliseconds(3) + microseconds(10) = 3010 μs hours(3) + minutes(10) = 190 m ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]s system_clock::now() = 129387415616250000 [1/10000000]s since Jan 1, 1970 monotonic_clock::now() = 37297387636417 ns since boot Set cout to use long names: high_resolution_clock::now() = 37297387655134 nanoseconds since boot
The μ for microsecond is specified to be U+00B5, encoded as UTF-8, UTF-16 or UTF-32 as appropriate for the stream's character size.
When the format decision is taken at runtime, it could be better to use
the parameterized manipulator duration_fmt
as in
duration_style style; //... cout << duration_fmt(style);
Parsing a duration
follows rules analogous
to the duration
converting constructor.
A value and a unit (SI symbol or prefixed) are read from the basic_istream
. If the duration
has an integral representation,
then the value parsed must be exactly representable in the target duration
(after conversion to
the target duration
units), else failbit
is set. duration
s based on floating-point
representations can be parsed using any units that do not cause overflow.
For example a stream containing "5000 milliseconds" can be
parsed into seconds, but if the stream contains "3001 ms",
parsing into seconds
will cause failbit
to
be set.
Example:
#include <boost/chrono/chrono_io.hpp> #include <sstream> #include <cassert> int main() { using namespace std; istringstream in("5000 milliseconds 4000 ms 3001 ms"); boost::chrono::seconds d(0); in >> d; assert(in.good()); assert(d == seconds(5)); in >> d; assert(in.good()); assert(d == seconds(4)); in >> d; assert(in.fail()); assert(d == seconds(4)); return 0; }
Note that a duration
failure may occur late
in the parsing process. This means that the characters making up the
failed parse in the stream are usually consumed despite the failure to
successfully parse.
Sometimes in templated code it is difficult to know what the unit of your duration is. It is all deterministic, and inspect-able. But it can be inconvenient to do so, especially if you just need to print out a "debugging" statement. For example:
// round to nearest, to even on tie
template <class To
, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
To t0 = duration_cast<To>(d);
To t1 = t0;
++t1;
auto diff0 = d - t0;
cout << "diff0 = " << diff0 << '\n';
auto diff1 = t1 - d;
cout << "diff1 = " << diff1 << '\n';
if (diff0 == diff1)
{
if (t0.count() & 1)
return t1;
return t0;
}
else if (diff0 < diff1)
return t0;
return t1;
}
This is where I/O for duration really shines. The compiler knows what the type of diff0 is and with this proposal that type (with proper units) will automatically be printed out for you. For example:
milliseconds ms = round<milliseconds>(nanoseconds(123)); // diff0 = 123 nanoseconds // diff1 = 999877 nanoseconds milliseconds ms = round<milliseconds>(Ticks(44)); // diff0 = 2 [1/3000]seconds // diff1 = 1 [1/3000]second
This simple I/O will make duration so much more accessible to programmers.
system_clock
is special. It
is the only clock that has conversions between its time_point
and time_t
. C subsequently
relates time_t to the Gregorian
calendar via ctime
,
gmtime
, localtime
, and strftime
.
Neither C, nor POSIX relate time_t
to any calendar other than the Gregorian
calendar. ISO 8601 is specified only in terms of the Gregorian
calendar.
Boost.Chrono provides system_clock::time_point
I/O in terms of the Gregorian
calendar, and no other calendar. However as system_clock::time_point
remains convertible with time_t
,
it is possible for clients to create other calendars which interoperate
with time_t
and subsequently
system_clock::time_point
.
Furthermore, it is existing practice for all major hosted operating systems
to store system time in a format which facilitates display as Coordinated
Universal Time (UTC). Therefore Boost.Chrono
provides that the default output for system_clock::time_point
be in a format that represents a point in time with respect to UTC.
cout << system_clock::now() << '\n';
could output
2011-09-15 18:36:59.325132 +0000
This format is strongly influenced by ISO 8601, but places a ' ' between the date and time instead of a 'T'. The former appears to more accurately represent existing practice. A fully numeric format was chosen so as to be understandable to as large a group of human readers as possible. A 24 hour format was chosen for the same reasons.
Of the referenced standards, only ISO 8601 discusses the output of fractional
seconds. Neither C nor POSIX have built-in functionality for this. However
it appears to be universal (as of this writing) that system_clock::period
is sub-second. And it seems desirable that if you stream out a system_clock::time_point
, you ought to be able to
stream it back in and get the same value. Therefore the streaming of
fractional seconds (at least by default) appears to be unavoidable.
Finally the trailing " +0000" disambiguates the UTC-formatted
system_clock::time_point
from one formatted with
respect to the local time zone of the computer. The latter can easily
be achieved with:
cout << time_fmt(local) << system_clock::now() << '\n';
that could result in
2011-09-15 14:36:59.325132 -0400
Note that system_clock::time_point
itself is neither UTC, nor the local time. However in practice, system_clock::time_point
is a count of ticks beyond
some epoch which is synchronized with UTC. So as a mobile computer moves
across time zones, the time zone traversal does not impact the value
of a system_clock::time_point
produced by system_clock::now()
.
And it is only in formatting it for human consumption that one can choose
UTC or the local time zone. C and POSIX treat time_t
just as Boost.Chrono treats system_clock::time_point
:
tm* gmtime(const time_t* timer) -> UTC tm* localtime(const time_t* timer) -> local time
This proposal simply extends the C/POSIX time_t
functionality to C++ syntax and system_clock::time_point
.
The time_fmt()
manipulator is "sticky". It will remain in effect until the
stream destructs or until it is changed. The stream can be reset to its
default state with:
cout << time_fmt(utc);
And the formatting can be further customized by using the time format sequences. For example:
cout << time_fmt(local, "%A %B %e, %Y %r"); cout << system_clock::now() << '\n'; // Sunday April 24, 2011 02:36:59 PM
When specifying formatting manipulators for wide streams, use wide strings.
You can use the same manipulators with istreams to specify parsing sequences.
Unfortunately there are no formatting/parsing sequences which indicate
fractional seconds. Boost.Chrono does
not provide such sequences. In the meantime, one can format and parse
fractional seconds for system_clock::time_point
by defaulting the format, or by using an empty string in time_fmt()
.
The stream's current locale may impact the parsing/format sequences supplied
to the system_clock::time_point
manipulators (e.g. names
of days of the week, and names of months).
Unlike system_clock::time_point
, the other clocks have no
conversion with time_t
.
There is likely no relationship between steady_clock::time_point and
UTC at all (UTC is not steady).
In general a time_point
is formatted by outputting
its internal duration
followed by a string
that describes the time_point
::clock
epoch. This string will vary
for each distinct clock, and for each implementation of the supplied
clocks.
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY cout << "steady_clock::now() = " << boost::chrono::steady_clock::now() << '\n'; #endif cout << "\nSet cout to use long names:\n" << boost::chrono::duration_long << "high_resolution_clock::now() = " << boost::chrono::high_resolution_clock::now() << '\n';
The output could be
steady_clock::now() = 37297387636417 ns since boot Set cout to use long names: high_resolution_clock::now() = 37297387655134 nanoseconds since boot
Parsing a time_point
involves first parsing
a duration
and then parsing the
epoch string. If the epoch string does not match that associated with
time_point::clock
then failbit will be set.
Example:
#include <boost/chrono/chrono_io.hpp> #include <sstream> #include <iostream> #include <cassert> int main() { using namespace std; boost::chrono::high_resolution_clock::time_point t0 = boost::chrono::high_resolution_clock::now(); stringstream io; io << t0; boost::chrono::high_resolution_clock::time_point t1; io >> t1; assert(!io.fail()); cout << io.str() << '\n'; cout << t0 << '\n'; cout << t1 << '\n'; boost::chrono::high_resolution_clock::time_point t = boost::chrono::high_resolution_clock::now(); cout << t << '\n'; cout << "That took " << t - t0 << '\n'; cout << "That took " << t - t1 << '\n'; return 0; }
The output could be:
50908679121461 nanoseconds since boot That took 649630 nanoseconds
Here's a simple example to find out how many hours the computer has been up (on this platform):
#include <boost/chrono/chrono_io.hpp> #include <iostream> int main() { using namespace std; using namespace boost; typedef boost::chrono::time_point<boost::chrono::steady_clock, boost::chrono::duration<double, boost::ratio<3600> > > T; T tp = boost::chrono::steady_clock::now(); std::cout << tp << '\n'; return 0; }
The output could be:
17.8666 hours since boot
The I/O interface described in the preceding I/O sections were at the user level. These services are based on low level services that are useful when writing libraries. The low level services are related to access to the associated ios state and locale facets. The design follows the C++ IOStreams standard design:
The library encapsulate the locale-dependent parsing and formatting of
duration
into a new facet class.
Let's focus on formatting in this example. The concerned facet class
is duration_put
, analogous to time_put,
money_put, etc.
The use of this facet is similar to the time_put facet.
Next we show how to override the duration
's default constructor
to do anything you want (in this case set it to zero). All we need to
do is to change the representation
namespace I_dont_like_the_default_duration_behavior { template <class R> class zero_default { public: typedef R rep; private: rep rep_; public: zero_default(rep i = 0) : rep_(i) {} operator rep() const {return rep_;} zero_default& operator+=(zero_default x) {rep_ += x.rep_; return *this;} zero_default& operator-=(zero_default x) {rep_ -= x.rep_; return *this;} zero_default& operator*=(zero_default x) {rep_ *= x.rep_; return *this;} zero_default& operator/=(zero_default x) {rep_ /= x.rep_; return *this;} zero_default operator+ () const {return *this;} zero_default operator- () const {return zero_default(-rep_);} zero_default& operator++() {++rep_; return *this;} zero_default operator++(int) {return zero_default(rep_++);} zero_default& operator--() {--rep_; return *this;} zero_default operator--(int) {return zero_default(rep_--);} friend zero_default operator+(zero_default x, zero_default y) {return x += y;} friend zero_default operator-(zero_default x, zero_default y) {return x -= y;} friend zero_default operator*(zero_default x, zero_default y) {return x *= y;} friend zero_default operator/(zero_default x, zero_default y) {return x /= y;} friend bool operator==(zero_default x, zero_default y) {return x.rep_ == y.rep_;} friend bool operator!=(zero_default x, zero_default y) {return !(x == y);} friend bool operator< (zero_default x, zero_default y) {return x.rep_ < y.rep_;} friend bool operator<=(zero_default x, zero_default y) {return !(y < x);} friend bool operator> (zero_default x, zero_default y) {return y < x;} friend bool operator>=(zero_default x, zero_default y) {return !(x < y);} }; typedef boost::chrono::duration
<zero_default<long long>, boost::nano > nanoseconds; typedef boost::chrono::duration
<zero_default<long long>, boost::micro > microseconds; typedef boost::chrono::duration
<zero_default<long long>, boost::milli > milliseconds; typedef boost::chrono::duration
<zero_default<long long> > seconds; typedef boost::chrono::duration
<zero_default<long long>, boost::ratio<60> > minutes; typedef boost::chrono::duration
<zero_default<long long>, boost::ratio<3600> > hours; }
Usage
using namespace I_dont_like_the_default_duration_behavior; milliseconds ms; std::cout << ms.count() << '\n';
See the source file example/i_dont_like_the_default_duration_behavior.cpp
A "saturating" signed integral type is developed. This type
has +/- infinity and a NaN (like IEEE floating-point) but otherwise obeys
signed integral arithmetic. This class is subsequently used as the template
parameter Rep in boost::chrono::duration
to demonstrate a duration
class that does not silently ignore overflow.
See the source file example/saturating.cpp
Example round_up utility: converts d to To, rounding up for inexact conversions Being able to easily write this function is a major feature!
#include <boost/chrono.hpp> #include <boost/type_traits.hpp> #include <iostream> template <class To, class Rep, class Period> To round_up(boost::chrono::duration<Rep, Period> d) { To result = boost::chrono::duration_cast<To>(d); if (result < d) ++result; return result; }
To demonstrate interaction with an xtime-like facility:
struct xtime { long sec; unsigned long usec; }; template <class Rep, class Period> xtime to_xtime_truncate(boost::chrono::duration
<Rep, Period> d) { xtime xt; xt.sec = static_cast<long>(boost::chrono::duration_cast
<seconds
>(d).count()); xt.usec = static_cast<long>(boost::chrono::duration_cast
<microseconds
>(d -seconds
(xt.sec)).count()); return xt; } template <class Rep, class Period> xtime to_xtime_round_up(boost::chrono::duration
<Rep, Period> d) { xtime xt; xt.sec = static_cast<long>(boost::chrono::duration_cast
<seconds
>(d).count()); xt.usec = static_cast<unsigned long>(round_up<boost::chrono::microseconds
>(d - boost::chrono::seconds
(xt.sec)).count()); return xt; } microseconds from_xtime(xtime xt) { return boost::chrono::seconds
(xt.sec) + boost::chrono::microseconds
(xt.usec); } void print(xtime xt) { std::cout << '{' << xt.sec << ',' << xt.usec << "}\n"; }
Usage
xtime xt = to_xtime_truncate(seconds(3) + boost::chrono::milliseconds
(251)); print(xt); boost::chrono::milliseconds ms = boost::chrono::duration_cast
<boost::chrono::milliseconds
>(from_xtime(xt)); std::cout << ms.count() << " milliseconds\n"; xt = to_xtime_round_up(ms); print(xt); xt = to_xtime_truncate(boost::chrono::seconds(3) +nanoseconds
(999)); print(xt); xt = to_xtime_round_up(boost::chrono::seconds(3) +nanoseconds
(999)); print(xt);
See the source file xtime.cpp
Users can easily create their own clocks, with both points in time and time durations which have a representation and precision of their own choosing. For example if there is a hardware counter which simply increments a count with each cycle of the cpu, one can very easily build clocks, time points and durations on top of that, using only a few tens of lines of code. Such systems can be used to call the time-sensitive threading API's such as sleep, wait on a condition variable, or wait for a mutex lock. The API proposed herein is not sensitive as to whether this is a 300MHz clock (with a 3 1/3 nanosecond tick period) or a 3GHz clock (with a tick period of 1/3 of a nanosecond). And the resulting code will be just as efficient as if the user wrote a special purpose clock cycle counter.
#include <boost/chrono.hpp> #include <boost/type_traits.hpp> #include <iostream> template <long long speed> struct cycle_count { typedef typename boost::__ratio_multiply__<boost::ratio
<speed>, boost::mega
>::type frequency; // Mhz typedef typename boost::__ratio_divide__<boost::ratio
<1>, frequency>::type period; typedef long long rep; typedef boost::chrono::duration
<rep, period> duration; typedef boost::chrono::time_point
<cycle_count> time_point; static time_point now() { static long long tick = 0; // return exact cycle count return time_point(duration(++tick)); // fake access to clock cycle count } }; template <long long speed> struct approx_cycle_count { static const long long frequency = speed * 1000000; // MHz typedef nanoseconds duration; typedef duration::rep rep; typedef duration::period period; static const long long nanosec_per_sec = period::den; typedef boost::chrono::time_point
<approx_cycle_count> time_point; static time_point now() { static long long tick = 0; // return cycle count as an approximate number of nanoseconds // compute as if nanoseconds is only duration in the std::lib return time_point(duration(++tick * nanosec_per_sec / frequency)); } };
See the source file cycle_count.cpp
This example demonstrates the use of a timeval-like struct to be used
as the representation type for both duration
and time_point
.
class xtime { private: long tv_sec; long tv_usec; void fixup() { if (tv_usec < 0) { tv_usec += 1000000; --tv_sec; } } public: explicit xtime(long sec, long usec) { tv_sec = sec; tv_usec = usec; if (tv_usec < 0 || tv_usec >= 1000000) { tv_sec += tv_usec / 1000000; tv_usec %= 1000000; fixup(); } } explicit xtime(long long usec) { tv_usec = static_cast<long>(usec % 1000000); tv_sec = static_cast<long>(usec / 1000000); fixup(); } // explicit operator long long() const {return static_cast<long long>(tv_sec) * 1000000 + tv_usec;} xtime& operator += (xtime rhs) { tv_sec += rhs.tv_sec; tv_usec += rhs.tv_usec; if (tv_usec >= 1000000) { tv_usec -= 1000000; ++tv_sec; } return *this; } xtime& operator -= (xtime rhs) { tv_sec -= rhs.tv_sec; tv_usec -= rhs.tv_usec; fixup(); return *this; } xtime& operator %= (xtime rhs) { long long t = tv_sec * 1000000 + tv_usec; long long r = rhs.tv_sec * 1000000 + rhs.tv_usec; t %= r; tv_sec = static_cast<long>(t / 1000000); tv_usec = static_cast<long>(t % 1000000); fixup(); return *this; } friend xtime operator+(xtime x, xtime y) {return x += y;} friend xtime operator-(xtime x, xtime y) {return x -= y;} friend xtime operator%(xtime x, xtime y) {return x %= y;} friend bool operator==(xtime x, xtime y) { return (x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec); } friend bool operator<(xtime x, xtime y) { if (x.tv_sec == y.tv_sec) return (x.tv_usec < y.tv_usec); return (x.tv_sec < y.tv_sec); } friend bool operator!=(xtime x, xtime y) { return !(x == y); } friend bool operator> (xtime x, xtime y) { return y < x; } friend bool operator<=(xtime x, xtime y) { return !(y < x); } friend bool operator>=(xtime x, xtime y) { return !(x < y); } friend std::ostream& operator<<(std::ostream& os, xtime x) {return os << '{' << x.tv_sec << ',' << x.tv_usec << '}';} };
Clock based on timeval-like struct.
class xtime_clock { public: typedef xtime rep; typedef boost::micro period; typedef boost::chrono::duration<rep, period> duration; typedef boost::chrono::time_point<xtime_clock> time_point; static time_point now() { #if defined(BOOST_CHRONO_WINDOWS_API) time_point t(duration(xtime(0))); gettimeofday((timeval*)&t, 0); return t; #elif defined(BOOST_CHRONO_MAC_API) time_point t(duration(xtime(0))); gettimeofday((timeval*)&t, 0); return t; #elif defined(BOOST_CHRONO_POSIX_API) //time_point t(0,0); timespec ts; ::clock_gettime( CLOCK_REALTIME, &ts ); xtime xt( ts.tv_sec, ts.tv_nsec/1000); return time_point(duration(xt)); #endif // POSIX } };
Usage of xtime_clock
std::cout << "sizeof xtime_clock::time_point = " << sizeof(xtime_clock::time_point) << '\n'; std::cout << "sizeof xtime_clock::duration = " << sizeof(xtime_clock::duration) << '\n'; std::cout << "sizeof xtime_clock::rep = " << sizeof(xtime_clock::rep) << '\n'; xtime_clock::duration delay(boost::chrono::milliseconds(5)); xtime_clock::time_point start = xtime_clock::now(); while (xtime_clock::now() - start <= delay) {} xtime_clock::time_point stop = xtime_clock::now(); xtime_clock::duration elapsed = stop - start; std::cout << "paused " << boost::chrono::::nanoseconds(elapsed).count() << " nanoseconds\n";
See the source file example/timeval_demo.cpp
The user can define a function returning the earliest time_point
as follows:
template <classClock
, classDuration1
, classDuration2
> typename boost::common_type
<time_point
<Clock
,Duration1
>,time_point
<Clock
,Duration2
> >::type min(time_point
<Clock
,Duration1
> t1,time_point
<Clock
,Duration2
> t2) { return t2 < t1 ? t2 : t1; }
Being able to easily write this function is a major feature!
BOOST_AUTO(t1, system_clock::now() + seconds(3)); BOOST_AUTO(t2, system_clock::now() + nanoseconds(3)); BOOST_AUTO(t3, min(t1, t2));
See the source file example/min_time_point.cpp
#include <boost/chrono.hpp> #include <iostream> #include <iomanip> using namespace boost::chrono; template< classClock
> class timer { typenameClock
::time_point start; public: timer() : start(Clock
::now() ) {} typenameClock
::duration elapsed() const { returnClock
::now() - start; } double seconds() const { return elapsed().count() * ((double)Clock::period::num/Clock::period::den); } }; int main() { timer<system_clock
> t1; timer<steady_clock
> t2; timer<high_resolution_clock
> t3; std::cout << "Type the Enter key: "; std::cin.get(); std::cout << std::fixed << std::setprecision(9); std::cout << "system_clock-----------: " << t1.seconds() << " seconds\n"; std::cout << "steady_clock--------: " << t2.seconds() << " seconds\n"; std::cout << "high_resolution_clock--: " << t3.seconds() << " seconds\n";system_clock
::time_point d4 =system_clock
::now();system_clock
::time_point d5 =system_clock
::now(); std::cout << "\nsystem_clock latency-----------: " << (d5 - d4).count() << std::endl;steady_clock
::time_point d6 =steady_clock
::now();steady_clock
::time_point d7 =steady_clock
::now(); std::cout << "steady_clock latency--------: " << (d7 - d6).count() << std::endl;high_resolution_clock
::time_point d8 =high_resolution_clock
::now();high_resolution_clock
::time_point d9 =high_resolution_clock
::now(); std::cout << "high_resolution_clock latency--: " << (d9 - d8).count() << std::endl; std::time_t now =system_clock
::to_time_t(system_clock
::now()); std::cout << "\nsystem_clock::now() reports UTC is " << std::asctime(std::gmtime(&now)) << "\n"; return 0; }
The output of this program run looks like this:
See the source file example/await_keystroke.cpp
In the example above we take advantage of the fact that time_point
s convert as long
as they have the same clock, and as long as their internal duration
s convert. We also take
advantage of the fact that a duration
with a floating-point
representation will convert from anything. Finally the I/O system discovers
the more readable "hours" unit for our duration<double, ratio<3600>>
.
There are many other ways to format duration
s and time_point
s. For example see
ISO 8601.
Instead of coding every possibility into operator<<
, which would lead to significant
code bloat for even the most trivial uses, this document seeks to inform
the reader how to write custom I/O when desired.
As an example, the function below streams arbitrary duration
s to arbitrary basic_ostreams
using the format:
[-]d/hh:mm:ss.cc
Where:
d
is the number of
days
h
is the number of
hours
m
is the number of
minutes
ss.cc
is the number of seconds
rounded to the nearest
hundredth of a second
// format duration as [-]d/hh::mm::ss.cc template <class CharT, class Traits, class Rep, class Period> std::basic_ostream<CharT, Traits>& display(std::basic_ostream<CharT, Traits>& os, boost::chrono::duration<Rep, Period> d) { using namespace std; using namespace boost; typedef boost::chrono::duration<long long, boost::ratio<86400> > days; typedef boost::chrono::duration<long long, boost:centi> centiseconds; // if negative, print negative sign and negate if (d < boost::chrono::duration<Rep, Period>(0)) { d = -d; os << '-'; } // round d to nearest centiseconds, to even on tie centiseconds cs = boost::chrono::duration_cast<centiseconds>(d); if (d - cs > boost::chrono::milliseconds(5) || (d - cs == boost::chrono::milliseconds(5) && cs.count() & 1)) ++cs; // separate seconds from centiseconds boost::chrono::seconds s = boost::chrono::duration_cast<boost::chrono::seconds>(cs); cs -= s; // separate minutes from seconds boost::chrono::minutes m = boost::chrono::duration_cast<boost::chrono::minutes>(s); s -= m; // separate hours from minutes boost::chrono::hours h = boost::chrono::duration_cast<boost::chrono::hours>(m); m -= h; // separate days from hours days dy = boost::chrono::duration_cast<days>(h); h -= dy; // print d/hh:mm:ss.cc os << dy.count() << '/'; if (h < boost::chrono::hours(10)) os << '0'; os << h.count() << ':'; if (m < boost::chrono::minutes(10)) os << '0'; os << m.count() << ':'; if (s < boost::chrono::seconds(10)) os << '0'; os << s.count() << '.'; if (cs < boost::chrono::centiseconds(10)) os << '0'; os << cs.count(); return os; } int main() { using namespace std; using namespace boost; display(cout, boost::chrono::steady_clock::now().time_since_epoch() + boost::chrono::duration<long, boost::mega>(1)) << '\n'; display(cout, -boost::chrono::milliseconds(6)) << '\n'; display(cout, boost::chrono::duration<long, boost::mega>(1)) << '\n'; display(cout, -boost::chrono::duration<long, boost::mega>(1)) << '\n'; }
The output could be:
12/06:03:22.95 -0/00:00:00.01 11/13:46:40.00 -11/13:46:40.00
The C++11 standard library's multi-threading library requires the ability to deal with the representation of time in a manner consistent with modern C++ practices. Next is a simulation of this interface.
The non-member sleep functions can be emulated as follows:
namespace boost { namespace this_thread { template <class Rep, class Period> void sleep_for(const chrono::duration
<Rep, Period>& d) { chrono::microseconds
t = chrono::duration_cast
<chrono::microseconds
>(d); if (t < d) ++t; if (t > chrono::microseconds
(0)) std::cout << "sleep_for " << t.count() << " microseconds\n"; } template <classClock
, classDuration
> void sleep_until(const chrono::time_point
<Clock
,Duration
>& t) { using namespace chrono; typedeftime_point
<Clock
,Duration
> Time; typedefsystem_clock
::time_point SysTime; if (t >Clock
::now()) { typedef typenamecommon_type
<typename Time::duration, typename SysTime::duration>::type D; /* auto */ D d = t -Clock
::now(); microseconds us =duration_cast
<microseconds
>(d); if (us < d) ++us; SysTime st =system_clock
::now() + us; std::cout << "sleep_until "; detail::print_time(st); std::cout << " which is " << (st -system_clock
::now()).count() << " microseconds away\n"; } } }}
Next is the boost::thread::timed_mutex
modified functions
namespace boost { struct timed_mutex { // ... template <class Rep, class Period> bool try_lock_for(const chrono::duration
<Rep, Period>& d) { chrono::microseconds
t = chrono::duration_cast
<chrono::microseconds
>(d); if (t <= chrono::microseconds
(0)) return try_lock(); std::cout << "try_lock_for " << t.count() << " microseconds\n"; return true; } template <classClock
, classDuration
> bool try_lock_until(const chrono::time_point
<Clock
,Duration
>& t) { using namespace chrono; typedeftime_point
<Clock
,Duration
> Time; typedefsystem_clock
::time_point SysTime; if (t <=Clock
::now()) return try_lock(); typedef typenamecommon_type
<typename Time::duration, typenameClock
::duration>::type D; /* auto */ D d = t -Clock
::now(); microseconds us =duration_cast
<microseconds
>(d); SysTime st =system_clock
::now() + us; std::cout << "try_lock_until "; detail::print_time(st); std::cout << " which is " << (st -system_clock
::now()).count() << " microseconds away\n"; return true; } }; }
boost::thread::condition_variable
time related function
are modified as follows:
namespace boost { struct condition_variable { // ... template <class Rep, class Period> bool wait_for(mutex&, const chrono::duration
<Rep, Period>& d) { chrono::microseconds t = chrono::duration_cast
<chrono::microseconds>(d); std::cout << "wait_for " << t.count() << " microseconds\n"; return true; } template <classClock
, classDuration
> bool wait_until(mutex&, const chrono::time_point
<Clock
,Duration
>& t) { using namespace boost::chrono; typedeftime_point
<Clock
,Duration
> Time; typedefsystem_clock
::time_point SysTime; if (t <=Clock
::now()) return false; typedef typenamecommon_type
<typename Time::duration, typenameClock
::duration>::type D; /* auto */ D d = t -Clock
::now(); microseconds us =duration_cast
<microseconds
>(d); SysTime st =system_clock
::now() + us; std::cout << "wait_until "; detail::print_time(st); std::cout << " which is " << (st -system_clock
::now()).count() << " microseconds away\n"; return true; } }; }
Next follows how simple is the usage of this functions:
boost::mutex m; boost::timed_mutex mut; boost::condition_variable cv; using namespace boost; this_thread::sleep_for(chrono::seconds
(3)); this_thread::sleep_for(chrono::nanoseconds
(300)); chrono::system_clock
::time_point time_limit = chrono::system_clock
::now() + chrono::__seconds_(4) + chrono::milliseconds
(500); this_thread::sleep_until(time_limit); mut.try_lock_for(chrono::milliseconds
(30)); mut.try_lock_until(time_limit); cv.wait_for(m, chrono::minutes
(1)); // real code would put this in a loop cv.wait_until(m, time_limit); // real code would put this in a loop // For those who prefer floating-point this_thread::sleep_for(chrono::duration
<double>(0.25)); this_thread::sleep_until(chrono::system_clock
::now() + chrono::duration
<double>(1.5));
See the source file example/simulated_thread_interface_demo.cpp
Example use of output in French
#include <boost/chrono/chrono_io.hpp> #include <iostream> #include <locale> int main() { using namespace std; using namespace boost; using namespace boost::chrono; cout.imbue(locale(locale(), new duration_punct<char> ( duration_punct<char>::use_long, "secondes", "minutes", "heures", "s", "m", "h" ))); hours h(5); minutes m(45); seconds s(15); milliseconds ms(763); cout << h << ", " << m << ", " << s << " et " << ms << '\n'; }
Output is:
5 heures, 45 minutes, 15 secondes et 763 millisecondes
See the source file example/french.cpp
The most authoritative reference material for the library is the C++ Standards Committee's current Working Paper (WP). 20.11 Time utilities "time"
From Howard E. Hinnant, Walter E. Brown, Jeff Garland and Marc Paterno. Is very informative and provides motivation for key design decisions
From Terry Golubiewski. Is very informative and provides motivation for key design decisions
From Beman Dawes. This issue has been stated as NAD Future.