std::condition_variable_any::wait
template< class Lock > void wait( Lock& lock ); | (1) | (с C++11) |
template< class Lock, class Predicate > void wait( Lock& lock, Predicate stop_waiting ); | (2) | (с C++11) |
template< class Lock, class Predicate > bool wait( Lock& lock, std::stop_token stoken, Predicate stop_waiting ); | (3) | (с C++20) |
wait заставляет текущий поток заблокироваться до тех пор, пока переменная состояния не будет уведомлена или не произойдёт ложное пробуждение, необязательно циклично до тех пор, пока некоторое предикат не будет удовлетворён (bool(stop_waiting()) == true).
lock, блокирует текущий поток выполнения и добавляет его в список потоков, ожидающих *this. Поток будет разблокирован, когда выполнится notify_all() или notify_one(). Он также может быть разблокирован ложно. При разблокировании, независимо от причины, lock снова приобретается, и wait завершается.while (!stop_waiting())
{
wait(lock);
}Этот перегруз может быть использован для игнорирования ложных пробуждений при ожидании, пока определённое условие не станет истинным. Обратите внимание, что lock необходимо приобрести перед входом в этот метод, и он снова приобретается после выхода из wait(lock), что означает, что lock может использоваться для защиты доступа к stop_waiting().
condition_variable_any на время wait(), чтобы получить уведомление, если запрос остановки был сделан для данного stoken's связанного состояния остановки; тогда оно эквивалентно while (!stoken.stop_requested())
{
if (stop_waiting())
return true;
wait(lock);
}
return stop_waiting();stop_waiting оценён как true, независимо от того, был ли запрос остановки или нет.Если эти функции не выполняют пост-условия (lock заблокирован вызывающим потоком), вызывается std::terminate. Например, это может произойти, если повторная блокировка мьютекса выбросит исключение.
Параметры
| lock | - | объект типа Lock, удовлетворяющий требованиям BasicLockable, который должен быть заблокирован текущим потоком |
| stoken | - | std::stop_token для регистрации прерывания |
| stop_waiting | - | предикат, который возвращает false, если ожидание должно продолжаться (bool(stop_waiting()) == false). Подпись предикатной функции должна быть эквивалентна следующей:
|
Возвращаемое значение
stop_waiting()
Исключения
stop_waiting.Примечания
Эффекты notify_one()/notify_all() и каждой из трёх атомарных частей wait()/wait_for()/wait_until() (разблокировка+ожидание, пробуждение и блокировка) происходят в едином полном порядке, который можно рассматривать как порядок модификации атомарной переменной: порядок специфичен для данной переменной состояния. Это делает невозможным, например, задержку notify_one() и разблокировку потока, который начал ожидание сразу после вызова notify_one().
Пример
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
std::condition_variable_any cv;
std::mutex cv_m; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, []{ return i == 1; });
std::cerr << "...finished waiting. i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
std::cerr << "Notifying...\n";
}
cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
std::cerr << "Notifying again...\n";
}
cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}Возможный вывод:
Waiting... Waiting... Waiting... Notifying... Notifying again... ...finished waiting. i == 1 ...finished waiting. i == 1 ...finished waiting. i == 1
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применён к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| LWG 2135 | C++11 |
wait выбросил исключение при ошибке разблокировки/переблокировки | вызывает std::terminate |
См. также
| блокирует текущий поток до пробуждения переменной состояния или после указанного таймаута (публичный член-функция) |
|
| блокирует текущий поток до пробуждения переменной состояния или до достижения указанной временной точки (публичный член-функция) |
|
C документация для cnd_wait |
|
Внешние ссылки
| 1. | Статья The Old New Thing: Ложные пробуждения в переменных состояния Win32. |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable_any/wait