Spec-Zone.ru › C++

std::condition_variable::wait

void wait( std::unique_lock<std::mutex>& lock );
(1) (since C++11)
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );
(2) (since C++11)

wait вызывает блокировку текущего потока до получения уведомления от переменной состояния или до возникновения ложного пробуждения, при необходимости циклически повторяя ожидание до тех пор, пока не будет удовлетворено некоторое предикатное условие (bool(stop_waiting()) == true).

1) Атомарно разблокирует lock, блокирует текущий поток выполнения и добавляет его в список потоков, ожидающих уведомления от *this. Поток будет разблокирован, когда будет выполнено notify_all() или notify_one(). Он также может быть разблокирован ложно. При разблокировке, независимо от причины, lock снова приобретается, и wait завершается.
2) Эквивалентно
while (!stop_waiting())
{
    wait(lock);
}

Этот перегруз может использоваться для игнорирования ложных пробуждений при ожидании, пока определённое условие не станет истинным. Обратите внимание, что lock должно быть приобретено перед входом в этот метод, и оно снова приобретается после выхода из wait(lock) , что означает, что lock может использоваться для защиты доступа к stop_waiting().

Если эти функции не выполняют пост-условия (lock.owns_lock()==true и lock.mutex() заблокировано вызывающим потоком), вызывается std::terminate. Например, это может произойти, если повторное блокирование мьютекса выбросит исключение.

Параметры

lock - объект типа std::unique_lock<std::mutex>, который должен быть заблокирован текущим потоком
stop_waiting - предикат, возвращающий ​false, если ожидание должно быть продолжено (bool(stop_waiting()) == false).

Подпись предикатной функции должна быть эквивалентна следующей:

bool pred();​

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

(ничего)

Исключения

1) Не выбрасывает.
2) То же, что и (1), но также может распространять исключения, брошенные stop_waiting.

Примечания

Вызов этой функции, если lock.mutex() не заблокирован текущим потоком, является неопределённым поведением.

Вызов этой функции, если lock.mutex() не является тем же мьютексом, что и тот, который используется всеми другими потоками, в данный момент ожидающими той же переменной состояния, является неопределённым поведением.

Эффекты 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 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

См. также

wait_for
блокирует текущий поток до пробуждения переменной состояния или по истечении заданного интервала времени
(публичный член-функция)
wait_until
блокирует текущий поток до пробуждения переменной состояния или достижения заданного момента времени
(публичный член-функция)
C documentation
для 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/wait

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API