Ответ 1
Краткий ответ: по стандарту С++ 14 high_resolution_clock
НЕ предоставляет явную гарантию, которую вы ищете.
В настоящее время steady_clock
и system_clock
предоставляют лучшие и более явные гарантии. Тем не менее, большинство реализаций, вероятно, обеспечат продвижение HRC во время сна. Тем не менее, может быть предпочтительнее сделать свой собственный тип сглаживания. См. Разделы "РЕДАКТИРОВАТЬ" ниже и обсуждение в комментариях.
Длинный ответ:
черновик стандарта на самом деле неявно подтверждается (в примечании 30.2.4 "Технические характеристики синхронизации", примечание 5), что объекты Clock не, требуемый для продвижения, пока их связанный поток спал. Для контекста в этом разделе объясняется, как работают объекты таймера стандартной библиотеки; поведение таймера основано на поведении часов, используемых для его установки.
[Примечание: если часы не синхронизированы с постоянными часами, например, CPU time clock, эти тайм-ауты могут не обеспечивать полезную функциональность. - конечная нота]
Обратите внимание, что в этом случае "тайм-ауты могут не предоставлять полезную функциональность" означает, что если вы используете таймер для sleep_until
определенного времени в часах с использованием несинхронизированного (не реального времени) часов, ваш поток не будет просыпаться. Таким образом, примечание выше немного преуменьшает.
И, действительно, в спецификации Clock (20.13.3) нет ничего, что на самом деле требует синхронизации с устойчивыми часами.
Однако стандарт, по-видимому, неявно допускает две потенциальные псевдонимы для high_resolution_clock
в определении в 20.13.7.3:
high_resolution_clock
может быть синонимомsystem_clock
илиsteady_clock
.
steady_clock
, конечно, устойчив. system_clock
не, поскольку системное время может измениться (например, в результате обновления NTP) во время работы программы.
Однако system_clock
(20.13.7.1) есть все еще "часы реального времени":
Объекты класса
system_clock
представляют собой часы настенных часов из общесистемные часы реального времени.
Так что system_clock
не будет останавливаться, когда ваш поток спит.
Это подтверждает точку зрения Николь Боласа, что is_steady
может быть ложным для high_resolution_clock
, даже если часы ведут себя так, как вы ожидаете (т.е. Они продвигаются независимо от состояния связанного потока).
Исходя из этого, представляется разумным ожидать, что большинство основных реализаций будут использовать синхронизированные часы реального времени (т.е. синхронизированные) для high_resolution_clock
. Реализации, в конечном счете, полезны, и часы, как правило, менее полезны, если они не в реальном времени, особенно если они использовались с таймерами в соответствии с примечанием "полезная функциональность" выше.
Так как он не гарантирован, вы должны проверить поведение и/или документацию каждой реализации, которую хотите использовать.
РЕДАКТИРОВАТЬ: Я начал обсуждение в группе стандартов ISO С++ по этому вопросу, предполагая, что это является ошибкой в стандарте. Первый ответ от Говарда Хиннанта, который берет на себя ответственность за то, что он поставил его в стандарт, заслуживает цитирования:
Я не возражаю против устаревания
high_resolution_clock
с намерением удалить его после подходящего периода отсрочки. Реальность такова, что она всегда является typedef дляsteady_clock
илиsystem_clock
, и программисту лучше выбрать один из этих двух и узнать, что происходит с hes, чем выбратьhigh_resolution_clock
и получить некоторые другие часы с помощью рулона кости.
... Итак, мораль, согласно Хиннанту, не использует high_resolution_clock
.
ИЗМЕНИТЬ 2:
Проблема с high_resolution_clock
в соответствии с Hinnant заключается не столько в том, что вы, вероятно, столкнетесь с проблемой с HRC (хотя это возможно даже с соответствующим компилятором в соответствии с приведенным выше аргументом), но так как вы обычно не получается получить более низкое разрешение, чем вы могли, с одним из двух других часов (хотя вам нужно вручную сравнить свои разрешения в псевдониме типа или typedef, чтобы получить "несовместимые часы с максимальным разрешением" ), нет никакой конкретной выгоды. Таким образом, вам нужно взвесить риск того, что потоки будут спать навсегда при выполнении соответствующих реализаций в сравнении с семантической выгодой имени high_resolution_clock
и простотой/краткости, чтобы избежать просто сделать свой собственный typedef или тип-псевдоним.
Вот некоторый фактический код для различных подходов:
-
Используйте
static_assert
, чтобы проверить, действительно лиhigh_resolution_clock
накладывается на настоящие часы. Это, вероятно, никогда не будет срабатывать, а это означает, что вы автоматически получаете часы реального времени с высоким разрешением, не входя в свои собственные typedefs:static_assert( std::is_same<high_resolution_clock, steady_clock>::value || std::is_same<high_resolution_clock, system_clock>::value, "high_resolution_clock IS NOT aliased to one of the other standard clocks!");
-
Используйте HRC, если
high_resolution_clock::is_steady
истинно; в противном случае предпочитают часы с более высоким разрешением междуsystem_clock
иsteady_clock
. ПРИМЕЧАНИЕ, что еслиhigh_resolution_clock::is_steady
является ложным, это, вероятно, означает, что HRC будет псевдонимомsystem_clock
, и в этом случае вы в конечном итоге получите новый тип-псевдоним, который на самом деле тот же введитеhigh_resolution_clock
. Однако создание собственного псевдонима типа делает это явным и гарантирует, что даже реализация, связанная со злым, но совместимым, не будет иметь проблемы, описанной выше.using maxres_sys_or_steady = std::conditional< system_clock::period::den <= steady_clock::period::den, system_clock, steady_clock >::type; using maxres_nonsleeping_clock = std::conditional< high_resolution_clock::is_steady, high_resolution_clock, maxres_sys_or_steady >::type;