Переменные условия предоставляют примитивы синхронизации, используемые для блокировки потока до тех пор, пока какой-либо другой поток не получит уведомление о том, что какое-то условие выполнено, или пока не будет достигнуто системное время. Классcondition_variable предоставляет переменную условия, которая может ожидать только объекта типаunique_lock<mutex>, что обеспечивает максимальную эффективность на некоторых платформах. Классcondition_variable_any предоставляет переменную общего условия, которая может ожидать объектов типов блокировки, задаваемых пользователем.
Переменные условия позволяют одновременное призываниеwait,wait_for, wait_until,notify_one иnotify_all функций - членов.
Выполнениеnotify_one иnotify_all должно быть атомарным. Исполнениеwait,wait_forиwait_until должно быть выполнено в течение трех атомных частей:
Реализация должна вести себя так , как будто все расстрелыnotify_one,notify_allи каждую частьwait,wait_forиwait_until казни исполняются в одном неопределенном общем порядке в соответствии с ним «происходит до» порядка.
namespace std { class condition_variable; class condition_variable_any; void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); enum class cv_status { no_timeout, timeout }; }
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
Effects: Передает право владения блокировкой, связанной с,lk во внутреннюю память и расписания,cond чтобы получать уведомления, когда текущий поток завершается, после того, как все объекты продолжительности хранения потока, связанные с текущим потоком, были уничтожены. Это уведомление должно быть таким, как если бы:
lk.unlock(); cond.notify_all();
Synchronization: Подразумеваемыйlk.unlock() вызов упорядочивается после уничтожения всех объектов с продолжительностью хранения потока, связанной с текущим потоком.
[ Note: Поставляемая блокировка будет удерживаться до тех пор, пока поток не завершится, и необходимо следить за тем, чтобы это не привело к возникновению тупиковой ситуации из-за проблем с упорядочением блокировок. После вызоваnotify_all_at_thread_exit рекомендуется как можно скорее выйти из потока и чтобы в этом потоке не выполнялись блокирующие или трудоемкие задачи. ] — end note
[ Note: Пользователь несет ответственность за то, чтобы ожидающие потоки не ошибочно предполагали, что поток завершился, если они испытывают ложное пробуждение. Обычно это требует, чтобы ожидаемое условие удовлетворялось при удержании блокировкиlk, и чтобы эта блокировка не снималась и не запрашивалась повторно перед вызовомnotify_all_at_thread_exit. ] — end note
namespace std { class condition_variable { public: condition_variable(); ~condition_variable(); condition_variable(const condition_variable&) = delete; condition_variable& operator=(const condition_variable&) = delete; void notify_one() noexcept; void notify_all() noexcept; void wait(unique_lock<mutex>& lock); template <class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred); template <class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time); template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template <class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time); template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); using native_handle_type = implementation-defined; // See [thread.req.native] native_handle_type native_handle(); // See [thread.req.native] }; }
condition_variable();
Throws:system_error когда требуется исключение ([thread.req.exception]).
~condition_variable();
Requires: Не должно быть блокировок резьбы*this. [ Note: То есть все потоки должны быть уведомлены; впоследствии они могут заблокировать блокировку, указанную в ожидании. Это ослабляет обычные правила, которые требовали бы, чтобы все вызовы ожидания выполнялись до уничтожения. Только уведомление для разблокировки ожидания должно произойти до уничтожения. Пользователь должен позаботиться о том, что ни один из потоков не ждать*this когда был запущен деструктор, особенно когда ожидающие потоки вызова функции ожидания в цикле или с использованием перегрузокwait,wait_forилиwait_until что взять предикат. ] — end note
void notify_one() noexcept;
void notify_all() noexcept;
void wait(unique_lock<mutex>& lock);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait, wait_forилиwait_untilнитей).
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait, wait_forилиwait_untilнитей).
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
template <class Clock, class Duration>
cv_status wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait, wait_forилиwait_untilнитей).
Effects:
Атомарно звонитlock.unlock() и блокируется*this.
При разблокировке вызываетlock.lock() (возможно, блокировку по блокировке), затем возвращается.
Функция разблокируется при получении сигнала от вызоваnotify_one(), вызоваnotify_all(), истечения абсолютного тайм-аута ([thread.req.timing]), указанного с помощьюabs_time, или ложно.
Если функция завершается через исключение, онаlock.lock() должна вызываться до выхода из функции.
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
Returns:cv_status::timeout если истек абсолютный тайм-аут ([thread.req.timing]), указанный вabs_time , в противном случаеcv_status::no_timeout.
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]).
template <class Rep, class Period>
cv_status wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait,wait_forили wait_untilнитей).
Returns:cv_status::timeout если истек относительный тайм-аут ([thread.req.timing]), указанный вrel_time , в противном случаеcv_status::no_timeout.
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]).
template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait, wait_forилиwait_untilнитей).
Effects: Эквивалентен:
while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
[ Note: Возвращенное значение указывает, оценивается ли предикат true независимо от того, был ли установлен тайм-аут. ] — end note
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]) или любое исключение, созданноеpred.
template <class Rep, class Period, class Predicate>
bool wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time,
Predicate pred);
Requires:lock.owns_lock() являетсяtrue иlock.mutex() заблокирован вызывающим потоком, и либо
никакой другой поток не ожидает этогоcondition_variable объекта или
lock.mutex() возвращает то же значение для каждого изlock аргументов , поставляемых всех одновременно ожидания ( с помощьюwait,wait_forили wait_untilнитей).
Effects: Эквивалентен:
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[ Note: Блокировка отсутствует, еслиpred() изначальноtrue, даже если время ожидания уже истекло. ] — end note
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
[ Note: Возвращенное значение указывает, оценивается ли предикатtrue независимо от того, был ли установлен тайм-аут. ] — end note
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]) или любое исключение, созданноеpred.
Lock Типа должны отвечать BasicLockable требованиям. [ Note: Все стандартные типы мьютексов соответствуют этому требованию. Если используетсяLock тип, отличный от одного из стандартных типов мьютекса илиunique_lock оболочки для стандартного типа мьютексаcondition_variable_any, пользователь должен убедиться, что вся необходимая синхронизация выполняется по отношению к предикату, связанному сcondition_variable_any экземпляром. ] — end note
namespace std { class condition_variable_any { public: condition_variable_any(); ~condition_variable_any(); condition_variable_any(const condition_variable_any&) = delete; condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; template <class Lock> void wait(Lock& lock); template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred); template <class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template <class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template <class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template <class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); }; }
condition_variable_any();
Throws:bad_alloc илиsystem_error когда требуется исключение ([thread.req.exception]).
~condition_variable_any();
Requires: Не должно быть блокировок резьбы*this. [ Note: То есть все потоки должны быть уведомлены; впоследствии они могут заблокировать блокировку, указанную в ожидании. Это ослабляет обычные правила, которые требовали бы, чтобы все вызовы ожидания выполнялись до уничтожения. Только уведомление для разблокировки ожидания должно произойти до уничтожения. Пользователь должен позаботиться о том, что ни один из потоков не ждать*this когда был запущен деструктор, особенно когда ожидающие потоки вызова функции ожидания в цикле или с использованием перегрузокwait,wait_forилиwait_until что взять предикат. ] — end note
void notify_one() noexcept;
void notify_all() noexcept;
template <class Lock>
void wait(Lock& lock);
[ Note: Если какая-либо изwait функций завершается через исключение, не указывается,Lock удерживается ли она. Можно использоватьLock тип, который позволяет запрашивать это, напримерunique_lock оболочку. ] — end note
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
template <class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
template <class Lock, class Clock, class Duration>
cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
Effects:
Атомарно звонитlock.unlock() и блокируется*this.
При разблокировке вызываетlock.lock() (возможно, блокировку по блокировке) и возвращает.
Функция разблокируется при получении сигнала от вызоваnotify_one(), вызоваnotify_all(), истечения абсолютного тайм-аута ([thread.req.timing]), указанного с помощьюabs_time, или ложно.
Если функция завершается через исключение, онаlock.lock() должна вызываться до выхода из функции.
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
Returns:cv_status::timeout если истек абсолютный тайм-аут ([thread.req.timing]), указанный вabs_time , в противном случаеcv_status::no_timeout.
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]).
template <class Lock, class Rep, class Period>
cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
Returns:cv_status::timeout если истек относительный тайм-аут ([thread.req.timing]), указанный вrel_time , в противном случаеcv_status::no_timeout.
Remarks: Если функция не удовлетворяет постусловию,terminate() должна быть вызвана ([except.terminate]). [ Note: Это может произойти, если повторная блокировка мьютекса вызывает исключение. ] — end note
Throws: Исключения, связанные с тайм-аутом ([thread.req.timing]).
template <class Lock, class Clock, class Duration, class Predicate>
bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
Effects: Эквивалентен:
while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
[ Note: Блокировка отсутствует, еслиpred() она установлена изначальноtrueили если время ожидания уже истекло. ] — end note
[ Note: Возвращенное значение указывает, оценивается ли предикатtrue независимо от того, был ли установлен тайм-аут. ] — end note
template <class Lock, class Rep, class Period, class Predicate>
bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);