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) | реализует перемещаемую оболочку владения мьютексом (шаблон класса) |