assert(!f.valid());←
(2) f больше не действителен
assert(sf.valid());←
(3) sf теперь действителен
Здесь будущий результат f
в начальный момент действителен (1)
, потому что ссылается на асинхронное состояние обещания p
, но после передачи состояния объекту sf
результат f
оказывается недействительным (2), a sf
— действительным (3).
Как и для других перемещаемых объектов, передача владения для r-значения производится неявно, поэтому объект std::shared_future
можно сконструировать прямо из значения, возвращаемого функцией-членом get_future()
объекта std::promise
, например:
std::promise p;←
(1) Неявная передача владения
std::shared_future sf(p.get_future());
Здесь передача владения неявная; объект std::shared_future<>
конструируется из r-значения типа std::future
(1).
У шаблона std::future
есть еще одна особенность, которая упрощает использование std::shared_future
совместно с новым механизмом автоматического выведения типа переменной из ее инициализатора (см. приложение А, раздел А.6). В шаблоне std::future
имеется функция-член share()
, которая создает новый объект std::shared_future
и сразу передаёт ему владение. Это позволяет сделать код короче и проще для изменения:
std::promise<
std::map
SomeAllocator>::iterator> p;
auto sf = p.get_future().share();
В данном случае для sf
выводится тип std::shared_future::iterator>
, такое название произнести-то трудно. Если компаратор или распределитель изменятся, то вам нужно будет поменять лишь тип обещания, а тип будущего результата изменится автоматически.
Иногда требуется ограничить время ожидания события — либо потому что на время исполнения некоторого участка кода наложены жесткие ограничения, либо потому что поток может заняться другой полезной работой, если событие долго не возникает. Для этого во многих функциях ожидания имеются перегруженные варианты, позволяющие задать величину таймаута.
4.3. Ожидание с ограничением по времени
Все блокирующие вызовы, рассмотренные до сих пор, приостанавливали выполнение потока на неопределенно долгое время — до тех пор, пока не произойдёт ожидаемое событие. Часто это вполне приемлемого в некоторых случаях время ожидания желательно ограничить. Например, это может быть полезно, когда нужно отправить сообщение вида «Я еще жив» интерактивному пользователю или другому процессу или когда ожидание действительно необходимо прервать, потому что пользователь устал ждать и нажал Cancel.
Можно задать таймаут одного из двух видов: интервальный , когда требуется ждать в течение определённого промежутка времени (к примеру, 30 миллисекунд) или абсолютный , когда требуется ждать до наступления указанного момента (например, 17:30:15.045987023 UTC 30 ноября 2011 года). У большинства функций ожидания имеются оба варианта. Варианты, принимающие интервальный таймаут, оканчиваются словом _for
, а принимающие абсолютный таймаут — словом _until
.
Например, в классе std::condition_variable
есть по два перегруженных варианта функций-членов wait_for()
и wait_until()
, соответствующие двум вариантам wait()
— первый ждет поступления сигнала или истечения таймаута или ложного пробуждения, второй проверяет при пробуждении переданный предикат и возвращает управление, только если предикат равен true
(и условной переменной поступил сигнал) или истек таймаут.
Прежде чем переходить к детальному обсуждению функций с таймаутами, рассмотрим, как в С++ задается время, и начнем с часов.
С точки зрения стандартной библиотеки С++, часы — это источник сведений о времени. Точнее, класс часов должен предоставлять четыре элемента информации:
• текущее время now ;
• тип значения для представления времени, полученного от часов;
• величина такта часов;
• признак равномерного хода времени, такие часы называются стабильными .
Получить от часов текущее время можно с помощью статической функции-члена now()
; например, функция std::chrono::system_clock::now()
возвращает текущее время по системным часам. Тип точки во времени для конкретного класса часов определяется с помощью члена typedef time_point
, поэтому значение, возвращаемое функцией some_clock::now()
имеет тип some_clock::time_point
.
Тактовый период часов задается в виде числа долей секунды, которое определяется членом класса typedef period
; например, если часы тикают 25 раз в секунду, то член period
будет определён как std::ratio<1, 25>
, тогда как в часах, тикающих один раз в 2,5 секунды, член period
определён как std::ratio<5, 2>
. Если тактовый период не известен до начала выполнения программы или может изменяться во время работы, то period
можно определить как средний период, наименьший период или любое другое значение, которое сочтет нужным автор библиотеки. Нет гарантии, что тактовый период, наблюдаемый в любом конкретном прогоне программы, соответствует периоду, определённому с помощью члена period.
Читать дальше