2013-11-15 8 views
22

При написании функции на 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 минут.

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

+0

использовать '' wait_until' или sleep_until' примитивы? IOW, используйте крайний срок, а не тайм-аут – sehe

+0

@sehe Внутренние условия выполнения тайм-аута не относятся к этому вопросу (я не имею никакого контроля над ними). Я просто обеспокоен тем, какой тип использовать для таймаута в сигнатуре функции. – JohnCand

+0

Как насчет миллисекунд? Стандарт _kinda_ указывает время ожидания в миллисекундах. Также - типы 'std :: chrono' выражаются в соотношениях, поэтому вы можете использовать нецелые значения. – Tibor

ответ

24

При использовании 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 секунды единиц).

Update

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

Если вы хотите принять любойstd::chrono::duration, даже тот, который вы, возможно, придется truncate or round, то при переходе с удаленного ответа 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-определенные функции, такие как std::this_thread::sleep_for являются шаблонными, как sehe предполагает, именно по причине желания быть совместимы с каждым 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++ 1у, который мы надеемся, означает C++ 14:

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

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

I сначала попытался бы использовать 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)); 

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

В настоящее время доступны видео: https://www.youtube.com/watch?v=P32hvk8b13M :-)

+0

+1 это должен быть принятый ответ. Это меня так сильно смущает :) – sehe

+0

Я согласен с этим ответом и признаю, что чувствую себя неловко за то, что не пытался что-то такое очевидное. 'std :: chrono :: duration' действительно [имеет конструкторы, которые принимают другие типы продолжительности в качестве своих аргументов] (http://en.cppreference.com/w/cpp/chrono/duration/duration). – JohnCand

+0

Хотелось бы, чтобы я мог поддержать ваш ответ более одного раза, ваше обновление действительно оценено. Один крошечный вопрос о последующих действиях: что бы вы порекомендовали как тайм-аут «бесконечности» (т. Е. Не тайм-аут), если я не хочу использовать 0 для этого, также имея в виду возможное преобразование и переполнение подписей/без знака вопросы базовых типов? – JohnCand

1

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

Просто голова, так как вы пришли почти к тому же ответу, что и я. Посмотрите на мгновение ясности :) – sehe