Какой тип использовать для переменной времени ожидания в C++?
При написании функции в C++, которая принимает тайм-аут в качестве одного из аргументов, какой тип я должен использовать для самого аргумента тайм-аута?
Примером такой функции может быть:
void my_function(bool work_really_hard, timeout_type timeout)
{
// Do stuff, until timeout is reached.
}
Я думал об использовании std::chrono::seconds
за timeout_type
, но это не позволяет использовать любой тайм-аут в подсекундной сфере.
Когда используешь std::chrono::nanoseconds
вместо этого неудобно указывать, скажем, 10 минут.
Любой способ решить это разумным способом, сохраняя при этом подпись функции и вызовы аккуратными и простыми?
2 ответа
Когда вместо этого используется std::chrono:: наносекунды, громоздко указывать, скажем, 10 минут.
На самом деле, это никоим образом не делает его громоздким:
#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));
}
Выход:
600000000000
Единственный раз, когда у вас будут проблемы nanoseconds
если вы хотите передать что-то, что не будет точно преобразовано в nanoseconds
, такие как picoseconds
, или же duration<long, ratio<1, 3>>
(1/3 секунды).
Обновить
Я предполагал, что этот ответ будет дополнительной информацией для уже принятого ответа, который, как мне показалось, является хорошим ответом (по Сехе). Сехе порекомендовал шаблонное решение, которое я тоже считаю хорошим.
Если вы хотите принять любой std::chrono::duration
даже тот, который вам, возможно, придется укоротить или округлить, а затем пойти с удаленным ответом sehe - вот путь:
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);
}
Если по какой-то причине вы не хотите иметь дело с шаблонами и / или вы удовлетворены тем, что ваши клиенты должны указывать только единицы, которые точно конвертируются в std::chrono:nanoseconds
затем с помощью std::chrono:nanoseconds
как я покажу выше, это тоже вполне приемлемо.
Все std::chrono
"заранее определенные" единицы:
hours
minutes
seconds
milliseconds
microseconds
nanoseconds
неявно преобразуются в nanoseconds
и не повлечет за собой никакого усечения или ошибки округления. Переполнение не будет происходить, пока вы удерживаете его в пределах двух ярко-белых линий (неясное указание на то, чтобы оставить свой автомобиль на своей полосе движения). Пока продолжительность составляет +/- 292 года, вам не нужно беспокоиться о переполнении с этими предварительно определенными единицами.
Стандартные функции, такие как std::this_thread::sleep_for
как он полагает, именно по той причине, по которой он хочет быть совместимым с каждым chrono:duration
мыслимые (например, 1/3 фемтосекунды с плавающей точкой). Разработчик API должен решить, нужна ли ему такая большая гибкость в их собственном API.
Если мне теперь удалось запутать вас вместо того, чтобы уточнить, не беспокойтесь слишком сильно. Если вы решили использовать nanoseconds
, все будет работать точно, без ошибок усечения или округления, или клиент получит ошибку времени компиляции. Там не будет ошибки во время выполнения.
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.
И если клиент получает ошибку во время компиляции, он всегда может использовать duration_cast
чтобы обойти это:
my_function(true, duration_cast<nanoseconds>(picoseconds(100000.25))); // Ok
Для получения более подробной информации, пожалуйста, смотрите:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm
Сладкое обновление исходного кода в верхней части этого ответа. В C++1y, что, как мы надеемся, означает C++14:
using namespace std::literals;
my_function(true, 10min); // also ok, is equal to 600000000000 nanoseconds
Вопрос: Что бы вы порекомендовали в качестве тайм-аута "бесконечности" (т.е. не превышайте тайм-аут)
Сначала я попытался бы использовать API, который не занимал тайм-аут и подразумевал, что "он не истекает". Например condition_variable::wait
, Если бы у меня был контроль над API, я бы создал такую подпись без тайм-аута.
В противном случае, я бы создал серию "большой" 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>>
>;
И тогда я бы использовал одну из этих больших длительностей в моем звонке, например:
std::this_thread::sleep_for(years(3));
Я бы не пытался максимально использовать push_things (вы можете нарушить базовые предположения, которые сделала ОС, например). Просто произвольно выбирай что-то смехотворно большое (вроде 3 года). Это привлечет внимание вашего рецензента кода и, вероятно, приведет к информативному разговору.:-)
Теперь доступно в видео: https://www.youtube.com/watch?v=P32hvk8b13M:-)
Используйте параметр шаблона для типа тайм-аута и ожидайте одно из std::chrono
типы или что-то с похожим интерфейсом; это позволит вам пройти в любую единицу времени.
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));