Назад к вопросам
Middle
175
questionbank

Что такое условная переменная (conditional variable)?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Условная переменная — это примитив синхронизации, используемый для организации взаимодействия между потоками. Она позволяет потоку (или потокам) ждать наступления определенного условия, пока другой поток не уведомит его (их) о выполнении этого условия. Обычно используется совместно с мьютексом для обеспечения атомарности проверки условия и ожидания.

Основные операции:

  • wait(mutex): Поток блокируется до тех пор, пока не будет получен сигнал. Перед блокировкой мьютекс атомарно освобождается. После получения сигнала мьютекс атомарно захватывается снова.
  • notify_one(): Разблокирует один поток из тех, кто ждет на этой условной переменной.
  • notify_all(): Разблокирует все потоки, которые ждут на этой условной переменной.

Проблема ложных пробуждений (spurious wakeups): Поток может быть разбужен, даже если notify_one или notify_all не были вызваны. Поэтому ожидание на условной переменной всегда должно происходить в цикле, проверяющем условие.

Пример на C++ (используя std::condition_variable):

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

std::mutex mtx;
std::condition_variable cv;
bool ready = false;
std::vector<int> data;

void worker_thread() {
    std::unique_lock<std::mutex> lock(mtx);
    // Ждем, пока условие не станет истинным
    cv.wait(lock, []{ return ready; });

    // Условие выполнено, работаем с данными
    std::cout << "Worker thread processing data: ";
    for (int d : data) {
        std::cout << d << " ";
    }
    std::cout << std::endl;

    // lock автоматически освобождается при выходе из функции
}

int main() {
    std::thread worker(worker_thread);

    // Подготавливаем данные
    {
        std::lock_guard<std::mutex> lock(mtx);
        data = {1, 2, 3, 4, 5};
        ready = true; // Устанавливаем условие
    } // lock_guard освобождает мьютекс

    // Уведомляем ожидающий поток
    cv.notify_one();

    worker.join();

    return 0;
}