Выбрать главу

Разобравшись с интервалами, мы можем перейти к моментам времени.

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>

полную версию книги