Разобравшись с интервалами, мы можем перейти к моментам времени.
4.3.3. Моменты времени
Момент времени представляется конкретизацией шаблона класса std::chrono::time_point<>
, в первом параметре которой задаются используемые часы, а во втором — единица измерения (специализация шаблона std::chrono::duration<>
). Значением момента времени является промежуток времени (измеряемый в указанных единицах) с некоторой конкретной точки на временной оси, которая называется эпохой часов. Эпоха часов — это основополагающее свойство, однако напрямую его запросить нельзя, и в стандарте С++ оно не определено. Из типичных эпох можно назвать полночь (00:00) 1 января 1970 года и момент, когда в последний раз был загружен компьютер, на котором исполняется приложение. У разных часов может быть общая или независимые эпохи. Если у двух часов общая эпоха, то псевдоним типа typedef time_point
в одном классе может ссылаться на другой класс как на тип, ассоциированный с time_point
. Хотя узнать, чему равна эпоха, невозможно, вы можете получить время между данным моментом time_point
и эпохой с помощью функции-члена time_since_epoch()
, которая возвращает интервал.
Например, можно задать момент времени std::chrono::time_point <std::chrono::system_clock, std::chrono::minutes>
. Он представляет время по системным часам, выраженное в минутах, а не в естественных для этих часов единицах (как правило, секунды или доли секунды).
К объекту std::chrono::time_point<>
можно прибавить интервал или вычесть из него интервал — в результате получится новый момент времени. Например, std::chrono::high_resolution_clock::now() + std::chrono::nanoseconds(500)
соответствует моменту времени в будущем, который отстоит от текущего момента на 500 наносекунд. Это удобно для вычисления абсолютного таймаута, когда известна максимально допустимая продолжительность выполнения некоторого участка программы, и внутри этого участка есть несколько обращений к функциям с ожиданием или обращения к функциям, которые ничего не ждут, но предшествуют функции с ожиданием и занимают часть отведенного времени.
Можно также вычесть один момент времени из другого при условии, что они относятся к одним и тем же часам. В результате получиться интервал между двумя моментами. Это полезно для хронометража участков программы, например:
auto start = std::chrono::high_resolution_clock::now();
do_something();
auto stop = std::chrono::high_resolution_clock::now();
std::cout << "do_something() заняла "
<< std::chrono::duration<
double, std::chrono::seconds>(stop-start).count()
<< " секунд" << std::endl;
Однако параметр clock
объекта std::chrono::time_point<>
не только определяет эпоху. Если передать момент времени функции с ожиданием, принимающей абсолютный таймаут, то указанный в нем параметр clock
используется для измерения времени. Это существенно в случае, когда часы подводятся, потому что механизм ожидания замечает, что наказания часов изменились, и не дает функции вернуть управление, пока функция-член часов now()
не вернет значение, большее, чем задано в таймауте. Если часы подведены вперёд, то это может уменьшить общее время ожидания (измеренное но стабильным часам), а если назад — то увеличить.
Как и следовало ожидать, моменты времени применяются в вариантах функций с ожиданием, имена которых заканчиваются словом _until
. Как правило, таймаут задается в виде смещения от значения some-clock::now()
, вычисленного в определенной точке программы, хотя моменты времени, ассоциированные с системными часами, можно получить из time_t
с помощью статической функции-члена std::chrono::system_clock::to_time_point()
, если при планировании операций требуется использовать время в понятном пользователю масштабе. Например, если на ожидание события, связанного с условной переменной, отведено не более 500 мс, то можно написать такой код.
Листинг 4.11. Ожидание условной переменной с таймаутом
#include <condition_variable>
#include <mutex>
#include <chrono>