Вооружившись знаниями о том, как задавать таймауты, рассмотрим функции, в которых таймауты используются.
4.3.4. Функции, принимающие таймаут
Простейший случай использования таймаута — задание паузы в потоке, чтобы он не отнимал у других потоков время, когда ему нечего делать. Соответствующий пример был приведён в разделе 4.1, где мы в цикле опрашивали флаг «done». Для этого использовались функции std::this_thread::sleep_for()
и std::this_thread::sleep_until()
. Обе работают как будильник: поток засыпает либо на указанный интервал (в случае sleep_for()
), либо до указанного момента времени (в случае sleep_until()
). Функцию sleep_for()
имеет смысл применять в ситуации, описанной в разделе 4.1, когда что-то необходимо делать периодически и важна лишь продолжительность периода. С другой стороны, функция sleep_until()
позволяет запланировать пробуждение потока в конкретный момент времени, например: запустить в полночь резервное копирование, начать в 6 утра распечатку платёжной ведомости или приостановить поток до момента следующего обновления кадра при воспроизведении видео.
Разумеется, таймаут принимают не только функции типа sleep
. Выше мы видели, что таймаут можно задавать при ожидании условных переменных и будущих результатов. А также при попытке захватить мьютекс, если сам мьютекс такую возможность поддерживает. Обычные классы std::mutex
и std::recursive_mutex
не поддерживают таймаут при захвате, зато его поддерживают классы std::timed_mutex
и std::recursive_timed_mutex
. В том и в другом имеются функции-члены try_lock_for()
и try_lock_until()
, которые пытаются получить блокировку в течение указанного интервала или до наступления указанного момента времени. В табл. 4.1 перечислены функции из стандартной библиотеки С++, которые принимают таймауты, их параметры и возвращаемые значения. Параметр duration
должен быть объектом типа std::duration<>
, а параметр time_point
— объектом типа std::time_point<>
.
Таблица 4.1. Функции, принимающие таймаут
Класс / пространство имен |
Функции |
Возвращаемые значения |
std::this_thread пространство имен |
sleep_for( duration ) sleep_until( time_point ) |
Неприменимо |
std::condition_variable или std::condition_variable_any |
wait_for( lock , duration ) wait_until( lock , time_point ) |
std::cv_status::timeout или std::cv_status::no_timeout |
|
wait_for( lock , duration , predicate ) wait_until( lock , time_point , predicate ) |
bool — значение, возвращенное предикатом predicate при пробуждении |
std::timed_mutex или std::recursive_timed_mutex |
try_lock_for( duration ) try_lock_until( time_point ) |
bool — true , если мьютекс захвачен, иначе false |
std::unique_lock< TimedLockable> |
unique_lock( lockable , duration ) unique_lock( lockable , time_point ) |
Неприменимо — функция owns_lock() для вновь сконструированного объекта возвращает true , если мьютекс захвачен, иначе false |
|
try_lock_for( duration ) try_lock_until( time_point ) |
bool — true , если мьютекс захвачен, иначе false |
std::future или std::shared_future |
wait_for( duration ) wait_until( time_point ) |
std::future_status::timeout , если истек таймаут, std::future_status::ready , если будущий результат готов, std::future_status::deferred , если в будущем результате хранится отложенная функция, которая еще не начала исполняться |
Теперь, когда мы рассмотрели условные переменные, будущие результаты, обещания и упакованные задачи, настало время представить более широкую картину их применения для синхронизации операций, выполняемых в разных потоках.
4.4. Применение синхронизации операций для упрощения кода
Использование описанных выше средств синхронизации в качестве строительных блоков позволяет сосредоточиться на самих нуждающихся в синхронизации операциях, а не на механизмах реализации. В частности, код можно упростить, применяя более функциональный (в смысле функционального программирования ) подход к программированию параллелизма. Вместо того чтобы напрямую разделять данные между потоками, мы можем снабдить каждый поток необходимыми ему данными, а результаты вычисления предоставить другим потокам, которые в них заинтересованы, с помощью будущих результатов.
Читать дальше