std::condition_variable
Определено в заголовочном файле <condition_variable>
|
||
class condition_variable; |
(начиная с C++11) | |
Класс condition_variable
это примитив синхронизации, который можно использовать для блокировки потока или нескольких потоков одновременно, пока другой поток не изменит совместно используемую переменную (условие) и не уведомит condition_variable
.
Поток, который намеревается изменить общую переменную, должен
- получить
std::mutex
(обычно через std::lock_guard) - выполнить модификацию, пока блокировка удерживается
- выполнить notify_one или notify_all для
std::condition_variable
(блокировку не требуется удерживать для уведомления)
Даже если общая переменная является атомарной, она должна быть изменена в мьютексе, чтобы правильно опубликовать изменение в ожидающем потоке.
Любой поток, который намеревается ожидать std::condition_variable
, должен
- получить std::unique_lock<std::mutex> на том же мьютексе, который используется для защиты общей переменной
- либо
- проверить состояние, если оно уже было обновлено и уведомлено
- выполнить wait, wait_for или wait_until. Операции ожидания атомарно освобождают мьютекс и приостанавливают выполнение потока.
- Когда условная переменная уведомляется, истекает тайм-аут или происходит ложное пробуждение, поток пробуждается, и мьютекс повторно запрашивается атомарно. Затем поток должен проверить условие и возобновить ожидание, если пробуждение было ложным.
- или
- используйте предикативную перегрузку 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
это StandardLayoutType. Он не является CopyConstructible, MoveConstructible, CopyAssignable или MoveAssignable.
Содержание |
[править] Типы-элементы
Тип-элемент | Определение |
native_handle_type
|
определено реализацией |
[править] Функции-элементы
создаёт объект (public функция-элемент) | |
разрушает объект (public функция-элемент) | |
operator= [удалено] |
без копирования присваиванием (public функция-элемент) |
Уведомление | |
уведомляет один ожидающий поток (public функция-элемент) | |
уведомляет все ожидающие потоки (public функция-элемент) | |
Одидание | |
блокирует текущий поток до тех пор, пока условная переменная не будет активирована (public функция-элемент) | |
блокирует текущий поток до тех пор, пока условная переменная не будет активирована или по истечении указанного времени ожидания (public функция-элемент) | |
блокирует текущий поток до тех пор, пока условная переменная не будет активирована или пока не будет достигнут указанный момент времени (public функция-элемент) | |
Встроенный дескриптор | |
возвращается системный дескриптор (public функция-элемент) |
[править] Пример
condition_variable
используется в сочетании с std::mutex для облегчения взаимодействия между потоками.
#include <iostream> #include <string> #include <thread> #include <mutex> #include <condition_variable> std::mutex m; std::condition_variable cv; std::string data; bool ready = false; bool processed = false; void worker_thread() { // Ждёт, пока main() отправит данные std::unique_lock lk(m); cv.wait(lk, []{return ready;}); // после ожидания мы владеем блокировкой. std::cout << "Поток worker обрабатывает данные\n"; data += " после обработки"; // Отправляет данные обратно в main() processed = true; std::cout << "Поток worker сигнализирует о завершении обработки данных\n"; // Ручная разблокировка выполняется перед уведомлением, чтобы не разбудить // ожидающий поток только для повторной блокировки (подробности смотрите в notify_one) lk.unlock(); cv.notify_one(); } int main() { std::thread worker(worker_thread); data = "Пример данных"; // отправляет данные в поток worker { std::lock_guard lk(m); ready = true; std::cout << "main() сигнализирует о готовности данных к обработке\n"; } cv.notify_one(); // ожидание worker { std::unique_lock lk(m); cv.wait(lk, []{return processed;}); } std::cout << "Возвращение в main(), data = " << data << '\n'; worker.join(); }
Вывод:
main() сигнализирует о готовности данных к обработке Поток worker обрабатывает данные Поток worker сигнализирует о завершении обработки данных Возвращение в main(), data = Пример данных после обработки
[править] Смотрите также
(C++11) |
предоставляет условную переменную, связанную с любым типом блокировки (класс) |
(C++11) |
обеспечивает базовую функциональность взаимного исключения (класс) |
(C++11) |
реализует обёртку владения мьютексом строго в области видимости (шаблон класса) |
(C++11) |
реализует перемещаемую оболочку владения мьютексом (шаблон класса) |