Ответ
std::condition_variable — это примитив синхронизации из стандартной библиотеки C++ (<condition_variable>), который позволяет одному или нескольким потокам ожидать (блокироваться) до тех пор, пока не будет выполнено некоторое условие, или пока их не уведомит другой поток. Он всегда используется в паре с std::mutex для защиты общего условия от гонок данных.
Основные методы:
wait(std::unique_lock<std::mutex>& lock, Predicate pred): Блокирует текущий поток. Автоматически освобождаетlockи ждет уведомления. После пробуждения повторно захватываетlockи проверяет предикатpred. Если предикат возвращаетfalse, поток снова засыпает. Это защищает от ложных пробуждений (spurious wakeups).notify_one(): Пробуждает один из ожидающих потоков (если такие есть).notify_all(): Пробуждает все ожидающие потоки.
Типичный паттерн "Ожидание условия":
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool data_ready = false;
int shared_data = 0;
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
// Ждем, пока флаг data_ready не станет true.
cv.wait(lock, []{ return data_ready; });
// После пробуждения мьютекс снова захвачен, данные безопасны.
std::cout << "Consumer received: " << shared_data << 'n';
}
void producer() {
// Имитируем подготовку данных
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard<std::mutex> lock(mtx);
shared_data = 42;
data_ready = true;
std::cout << "Producer sent data.n";
} // Мьютекс освобождается здесь
cv.notify_one(); // Уведомляем потребителя
}
int main() {
std::thread t1(consumer);
std::thread t2(producer);
t1.join();
t2.join();
return 0;
}
Важные замечания:
- Всегда используйте
std::unique_lockсcondition_variable, так какwait()должен уметь временно отпускать и снова захватывать мьютекс. - Изменение условия (
data_ready) и вызовnotify_*()должны выполняться под защитой того же мьютекса, чтобы избежать состояния гонки, когда уведомление отправляется до того, как потребитель начал ждать (потерянное уведомление). - Предикат в
wait()— это не просто синтаксический сахар, а необходимая защита от ложных пробуждений, которые разрешены стандартом.