Spec-Zone.ru › C++

std::condition_variable

Определён в заголовочном файле <condition_variable>
class condition_variable;
(начиная с C++11)

std::condition_variable — примитив синхронизации, используемый с std::mutex для блокировки одного или нескольких потоков до тех пор, пока другой поток не изменит общую переменную (условие) и не уведомит std::condition_variable.

Поток, который собирается изменить общую переменную, должен:

  1. Захватить std::mutex (обычно с помощью std::lock_guard).
  2. Изменить общую переменную, удерживая блокировку.
  3. Вызвать notify_one или notify_all для std::condition_variable (это можно сделать после снятия блокировки).

Даже если общая переменная является атомарной, её необходимо изменить, удерживая мьютекс, чтобы корректно опубликовать изменение для ожидающего потока.

Любой поток, который собирается ожидать на std::condition_variable, должен:

  1. Захватить std::unique_lock<std::mutex> для мьютекса, используемого для защиты общей переменной.
  2. Выполнить одно из следующих действий:
  1. Проверить условие на случай, если оно уже было обновлено и отправлено уведомление.
  2. Вызвать wait, wait_for или wait_until для std::condition_variable (атомарно освобождает мьютекс и приостанавливает выполнение потока до получения уведомления от переменной условия, истечения времени ожидания или возникновения ложного пробуждения, а затем перед возвратом атомарно захватывает мьютекс).
  3. Проверить условие и продолжить ожидание, если оно не выполнено.
или:
  1. Использовать перегрузку wait, wait_for и wait_until с предикатом, которая выполняет те же три шага.

std::condition_variable работает только с std::unique_lock<std::mutex>, что обеспечивает максимальную эффективность на некоторых платформах. std::condition_variable_any предоставляет переменную условия, которая работает с объектом любого типа BasicLockable, например std::shared_lock.

Переменные условия допускают одновременный вызов функций-членов wait, wait_for, wait_until, notify_one и notify_all.

Класс std::condition_variable является типом со стандартной компоновкой. Он не удовлетворяет требованиям CopyConstructible, MoveConstructible, CopyAssignable или MoveAssignable.

Вложенные типы

Имя Определение
native_handle_type определяется реализацией

Функции-члены

(конструктор)
создаёт объект
(открытая функция-член)
(деструктор)
уничтожает объект
(открытая функция-член)
operator=
[удалён]
копирующее присваивание недоступно
(открытая функция-член)
Уведомление
notify_one
уведомляет один ожидающий поток
(открытая функция-член)
notify_all
уведомляет все ожидающие потоки
(открытая функция-член)
Ожидание
wait
блокирует текущий поток до пробуждения переменной условия
(открытая функция-член)
wait_for
блокирует текущий поток до пробуждения переменной условия или истечения заданного времени ожидания
(открытая функция-член)
wait_until
блокирует текущий поток до пробуждения переменной условия или достижения указанного момента времени
(открытая функция-член)
Нативный дескриптор
native_handle
возвращает нативный дескриптор
(открытая функция-член)

Пример

std::condition_variable используется совместно с std::mutex для упрощения взаимодействия между потоками.

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // wait until main() sends data
    std::unique_lock lk(m);
    cv.wait(lk, []{ return ready; });
    
    // after the wait, we own the lock
    std::cout << "Worker thread is processing data\n";
    data += " after processing";
    
    // send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";
    
    // manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);
    
    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();
    
    // wait for the worker
    {
        std::unique_lock lk(m);
        cv.wait(lk, []{ return processed; });
    }
    std::cout << "Back in main(), data = " << data << '\n';
    
    worker.join();
}

Вывод:

main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing

См. также

condition_variable_any
(C++11)
предоставляет переменную условия, связанную с блокировкой любого типа
(класс)
mutex
(C++11)
предоставляет базовые средства взаимного исключения
(класс)
lock_guard
(C++11)
реализует оболочку владения мьютексом, строго ограниченную областью видимости
(шаблон класса)
unique_lock
(C++11)
реализует перемещаемую оболочку владения мьютексом
(шаблон класса)

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

Spec-Zone.ru

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