← Назад к вопросам
В чём разница между mutex и Condition Variables?
2.0 Middle🔥 161 комментариев
#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Mutex и Condition Variables
Это два связанных, но разных примитива синхронизации. Хотя они часто работают вместе, их роли принципиально отличаются.
Что такое Mutex?
Mutex (Mutual Exclusion) — это замок для защиты доступа к общему ресурсу. Его основная задача:
- Исключить одновременный доступ (только один поток может держать mutex в момент времени)
- Предотвратить race conditions при чтении/изменении данных
Пример:
#include <mutex>
std::mutex mtx;
int shared_counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // LOCK
shared_counter++; // безопасно
} // UNLOCK при разрушении lock_guard
Что такое Condition Variable?
Condition Variable — это механизм для синхронизации на уровне событий. Её назначение:
- Позволить одному потоку уведомить другой о наступлении события
- Блокировать поток, пока определённое условие не станет истинным
- Избежать busy-waiting (постоянного опроса)
Пример:
#include <condition_variable>
#include <mutex>
#include <thread>
std::mutex mtx;
std::condition_variable cv;
bool data_ready = false;
void producer() {
{
std::lock_guard<std::mutex> lock(mtx);
data_ready = true;
}
cv.notify_one(); // Сигнал потребителю
}
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return data_ready; }); // Ждём сигнала
// Обрабатываем данные
}
Ключевые отличия
| Аспект | Mutex | Condition Variable |
|---|---|---|
| Назначение | Синхронизация доступа к ресурсу | Синхронизация на уровне событий |
| Основная роль | Взаимное исключение | Ожидание/сигнализация |
| Используется с | - | Mutex (всегда!) |
| wait() | Нет | Да, блокирует поток |
| notify() | Нет | Да, пробуждает потоки |
| Busy-waiting? | Возможен | Нет |
Почему нужны оба?
Condition Variable требует mutex для:
- Защиты флага (например,
data_ready) - Гарантии атомарности проверки условия и ожидания
- Избегания race condition между проверкой и wait()
// ❌ НЕПРАВИЛЬНО — race condition
while (!data_ready) { // Проверили
cv.wait(mtx); // Между check и wait может измениться!
}
// ✅ ПРАВИЛЬНО — атомарно
cv.wait(lock, [] { return data_ready; });
Практический пример: Producer-Consumer
std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;
const int MAX_SIZE = 10;
void producer(int id) {
for (int i = 0; i < 5; i++) {
std::unique_lock<std::mutex> lock(mtx);
// Ждём, пока буфер не опустеет
cv.wait(lock, [] { return buffer.size() < MAX_SIZE; });
buffer.push(id * 100 + i);
std::cout << "Produced: " << buffer.back() << std::endl;
lock.unlock();
cv.notify_all(); // Уведомляем потребителей
std::this_thread::sleep_for(std::chrono::ms(100));
}
}
void consumer(int id) {
for (int i = 0; i < 5; i++) {
std::unique_lock<std::mutex> lock(mtx);
// Ждём, пока буфер не заполнится
cv.wait(lock, [] { return !buffer.empty(); });
int val = buffer.front();
buffer.pop();
std::cout << "Consumed: " << val << std::endl;
lock.unlock();
cv.notify_all(); // Уведомляем производителей
}
}
Когда что использовать?
- Только Mutex: защита простого доступа к данным (счётчик, флаг)
- Mutex + Condition Variable: когда один поток должен дождаться события другого (буфер, задача выполнена, данные загружены)
Запомни: CV без mutex = undefined behaviour. Mutex без CV = либо busy-waiting, либо неправильная синхронизация событий.