![]() |
Home | Libraries | People | FAQ | More |
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