What type to use for a timeout variable in C++?
When using std::chrono::nanoseconds instead, it is cumbersome to specify, say, 10 minutes.
Actually, it doesn't make it cumbersome in the least:
#include <chrono>
#include <iostream>
void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
{
std::cout << timeout.count() << '\n';
}
int main()
{
my_function(true, std::chrono::minutes(10));
}
Output:
600000000000
The only time you'll have trouble with nanoseconds
is if you want to pass in something that won't exactly convert to nanoseconds
, such as picoseconds
, or duration<long, ratio<1, 3>>
(1/3 second units).
Update
I intended this answer to be additional information for an already accepted answer that I thought was a good answer (by sehe). sehe recommended a templated solution, which I also consider fine.
If you want to accept any std::chrono::duration
, even one that you may have to truncate or round, then going with sehe's deleted answer is the way to go:
template <typename Rep, typename Period>
void my_function(bool work_really_hard, std::chrono::duration<Rep, Period> timeout)
{
// Do stuff, until timeout is reached.
std::this_thread::sleep_for(timeout);
}
If for some reason you do not want to deal with templates and/or you are content with having your clients having to specify only units that are exactly convertible to std::chrono:nanoseconds
, then using std::chrono:nanoseconds
as I show above is also completely acceptable.
All of the std::chrono
"pre-defined" units:
hours
minutes
seconds
milliseconds
microseconds
nanoseconds
are implicitly convertible to nanoseconds
, and will not involve any truncation or round off error. Overflow will not happen as long as you keep it within the two bright white lines (obscure reference to keeping your car in your own lane). As long as the duration is within +/- 292 years, you don't have to worry about overflow with these pre-defined units.
The std-defined functions such as std::this_thread::sleep_for
are templated as sehe suggests for exactly the reason of wanting to be interoperable with every chrono:duration
imaginable (e.g. 1/3 of a floating-point femtosecond). It is up to the API designer to decide if they need that much flexibility in their own API.
If I've now managed to confuse you instead of clarify, don't worry too much. If you choose to use nanoseconds
, things will either work exactly, with no truncation or round off error, or the client will get a compile time error. There will be no run time error.
void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
{
std::cout << timeout.count() << '\n';
}
int
main()
{
using namespace std;
using namespace std::chrono;
typedef duration<double, pico> picoseconds;
my_function(true, picoseconds(100000.25));
}
test.cpp:15:9: error: no matching function for call to 'my_function'
my_function(true, picoseconds(100000.25));
^~~~~~~~~~~
test.cpp:4:10: note: candidate function not viable: no known conversion from 'duration<double, ratio<[...], 1000000000000>>' to
'duration<long long, ratio<[...], 1000000000>>' for 2nd argument
void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
^
1 error generated.
And if the client gets a compile-time error, he can always use duration_cast
to work around it:
my_function(true, duration_cast<nanoseconds>(picoseconds(100000.25))); // Ok
For further details, please see:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm
Sweet update to the original code at the top of this answer. In C++1y, which we hope means C++14:
using namespace std::literals;
my_function(true, 10min); // also ok, is equal to 600000000000 nanoseconds
Question: What would you recommend as a timeout of "infinity" (i.e. don't time out)
I would first try to use an API that didn't take a timeout, and which implied "doesn't time out." For example condition_variable::wait
. If I had control over the API, I would create such a signature without a timeout.
Failing that, I would create a series a "large" chrono::durations
:
using days = std::chrono::duration
<
std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
>;
using weeks = std::chrono::duration
<
std::int32_t, std::ratio_multiply<days::period, std::ratio<7>>
>;
using years = std::chrono::duration
<
std::int32_t, std::ratio_multiply<days::period, std::ratio<146097, 400>>
>;
using months = std::chrono::duration
<
std::int32_t, std::ratio_divide<years::period, std::ratio<12>>
>;
And then I would use one of these large durations in my call, for example:
std::this_thread::sleep_for(years(3));
I would not try to push_things to the maximum (you might break the underlying assumptions the OS has made for example). Just arbitrarily pick something ridiculously large (like 3 years). That will catch your code reviewer's eye, and likely strike up an informative conversation. :-)
Now available in video: https://www.youtube.com/watch?v=P32hvk8b13M :-)
Use a template parameter for the timeout type and expect one of the std::chrono
types, or something with a similar interface; this will allow you to pass in any unit of time.
template<typename T>
void wait_a_while(const T& duration)
{
std::this_thread::sleep(duration);
}
wait_a_while(boost::posix_time::seconds(5));
wait_a_while(std::chrono::milliseconds(30));