Namespaces
Variants

std::condition_variable_any:: wait

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
template < class Lock >
void wait ( Lock & lock ) ;
(1) (начиная с C++11)
template < class Lock, class Predicate >
void wait ( Lock & lock, Predicate pred ) ;
(2) (начиная с C++11)
template < class Lock, class Predicate >
bool wait ( Lock & lock, std:: stop_token stoken, Predicate pred ) ;
(3) (начиная с C++20)

wait блокирует текущий поток до тех пор, пока не будет получено уведомление от условной переменной или не произойдет ложное пробуждение. pred может быть опционально предоставлен для обнаружения ложных пробуждений.

1) Атомарно вызывает lock. unlock ( ) и блокируется на * this .
Поток будет разблокирован, когда notify_all() или notify_one() будет выполнен. Также он может быть разблокирован спонтанно.
При разблокировке вызывает lock. lock ( ) (возможно блокируясь на блокировке), затем возвращает управление.
2,3) Ожидание выполнения определенного условия, может использоваться для игнорирования ложных пробуждений.
2) Эквивалентно
while ( ! pred ( ) )
wait ( lock ) ;
3) Регистрирует * this на время данного вызова для получения уведомления о запросе остановки в stoken 's связанном состоянии остановки; затем становится эквивалентно
while ( ! stoken. stop_requested ( ) )
{
if ( pred ( ) )
return true ;
wait ( lock ) ;
}
return pred ( ) ;

Сразу после того, как wait возвращает управление, lock блокируется вызывающим потоком. Если это постусловие не может быть выполнено [1] , вызывается std::terminate .

  1. Это может произойти, если повторная блокировка мьютекса вызывает исключение.

Содержание

Параметры

lock - блокировка, которая должна быть захвачена вызывающим потоком
stoken - токен остановки для регистрации прерывания
pred - предикат для проверки возможности завершения ожидания
Требования к типам
-
Lock должен удовлетворять требованиям BasicLockable .
-
Predicate должен удовлетворять требованиям FunctionObject .
-
pred ( ) должно быть валидным выражением, и его тип и категория значения должны удовлетворять требованиям BooleanTestable .

Возвращаемое значение

1,2) (нет)
3) Последний результат pred ( ) перед возвратом к вызывающей стороне.

Исключения

1) Не генерирует исключений.
2,3) Любое исключение, выброшенное pred .

Примечания

Возвращаемое значение перегрузки (3) указывает, оценивается ли pred как true , независимо от того, был ли запрошен останов или нет.

Эффекты 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; // Этот мьютекс используется для трёх целей:
                 // 1) для синхронизации доступа к i
                 // 2) для синхронизации доступа к std::cerr
                 // 3) для переменной условия 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 2114
( P2167R3 )
C++11 конвертируемость в bool была слишком слабой для отражения ожиданий реализаций требования усилены
LWG 2135 C++11 поведение было неясным, если lock. lock ( ) выбрасывает исключение вызывает std::terminate в этом случае

Смотрите также

блокирует текущий поток до пробуждения переменной условия или после указанной длительности таймаута
(public member function)
блокирует текущий поток до пробуждения переменной условия или до достижения указанной точки времени
(public member function)
C documentation для cnd_wait

Внешние ссылки

The Old New Thing статья: Ложные пробуждения в условных переменных Win32.