Подтвердить что ты не робот

Какой тип использовать для переменной тайм-аута в С++?

При написании функции в С++, которая принимает таймаут в качестве одного из своих аргументов, какой тип я должен использовать для самого аргумента таймаута?

Примером такой функции может быть:

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 минут.

Любой способ разрешить это разумным образом, сохраняя подпись функции и звонки аккуратно и просто?

4b9b3361

Ответ 1

При использовании std:: chrono:: nanoseconds вместо этого, это громоздко укажите, скажем, 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 секунды единиц).

Обновление

Я наметил этот ответ дополнительной информацией для уже принятого ответа, который, как я думал, был хорошим ответом (by sehe). sehe рекомендовал шаблонное решение, которое я также считаю прекрасным.

Если вы хотите принять любой std::chrono::duration, даже тот, который вам может понадобиться обрезать или округлить, то переход с удаленным ответом - путь:

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 функции, такие как 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

Сладкое обновление исходного кода в верхней части этого ответа. В С++ 1y, который, мы надеемся, означает С++ 14:

using namespace std::literals;
my_function(true, 10min);  // also ok, is equal to 600000000000 nanoseconds

Вопрос: Что бы вы порекомендовали в качестве тайм-аута "бесконечности" (т.е. не время ожидания)

Сначала я попытался использовать API, который не использовал тайм-аут, и подразумевал, что "не тайм-аут". Например condition_variable::wait. Если бы у меня был контроль над API, я бы создал такую ​​подпись без тайм-аута.

В противном случае я бы создал серию "большой" chrono::durations:

typedef std::chrono::duration
<
    std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
> days;

typedef std::chrono::duration
<
    std::int32_t, std::ratio_multiply<days::period, std::ratio<7>>
> weeks;

typedef std::chrono::duration
<
    std::int32_t, std::ratio_multiply<days::period, std::ratio<146097, 400>>
> years;

typedef std::chrono::duration
<
    std::int32_t, std::ratio_divide<years::period, std::ratio<12>>
> months;

И затем я бы использовал одну из этих больших длительностей в моем вызове, например:

std::this_thread::sleep_for(years(3));

Я бы не пытался максимально увеличить push_things (вы можете нарушить базовые предположения, сделанные ОС, например). Просто произвольно выберите что-то смехотворно большое (например, 3 года). Это поймает ваш глаз обзора кода и, вероятно, заинтересует информативный разговор.: -)

Теперь доступно на видео: https://www.youtube.com/watch?v=P32hvk8b13M: -)

Ответ 2

Используйте параметр шаблона для типа тайм-аута и ожидайте один из типов 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));