Spec-Zone.ru › C++

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

См. также

wait_for
блокирует текущий поток до пробуждения условной переменной или истечения заданного времени ожидания
(открытая функция-член)
wait_until
блокирует текущий поток до пробуждения условной переменной или наступления заданного момента времени
(открытая функция-член)
Документация C для cnd_wait

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

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/thread/condition_variable_any/wait

Spec-Zone.ru

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