Какой тип использовать для переменной времени ожидания в 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));
Другие вопросы по тегам