Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что делает Mutex?
Определение
Mutex (Mutual Exclusion) — синхронизационный примитив, обеспечивающий эксклюзивный доступ к ресурсу. Только один поток может одновременно захватить mutex, остальные потоки ждут.
Основная задача
Mutex предотвращает race conditions, когда несколько потоков одновременно обращаются к одному ресурсу, приводя к неопределённому поведению.
Пример проблемы (Race Condition)
#include <iostream>
#include <thread>
using namespace std;
int counter = 0;
void increment() {
for (int i = 0; i < 1000000; ++i) {
counter++; // RACE CONDITION!
}
}
int main() {
thread t1(increment), t2(increment), t3(increment);
t1.join(); t2.join(); t3.join();
cout << counter << endl;
// Ожидаем: 3000000
// Получим: 1523847 (разное каждый раз!)
}
Почему? Операция counter++ это три машинных инструкции:
1. LOAD counter (из памяти)
2. INC (инкрементируем)
3. STORE (обратно в память)
Потоки выполняют эти шаги одновременно и перезаписывают друг друга.
Решение с Mutex
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int counter = 0;
mutex mtx; // Mutex для защиты
void increment() {
for (int i = 0; i < 1000000; ++i) {
mtx.lock(); // Захватываем
counter++; // Критическая секция
mtx.unlock(); // Освобождаем
}
}
int main() {
thread t1(increment), t2(increment), t3(increment);
t1.join(); t2.join(); t3.join();
cout << counter << endl; // Теперь: 3000000
}
RAII подход (лучше)
void increment() {
for (int i = 0; i < 1000000; ++i) {
lock_guard<mutex> guard(mtx); // Автоматическое захватывание
counter++; // Защищённый код
} // Автоматическое освобождение
}
Типы Mutex в C++
1. std::mutex — базовый
mutex mtx;
mtx.lock(); // Захватить
mtx.unlock(); // Освободить
bool ok = mtx.try_lock(); // Попытка без блокировки
2. std::recursive_mutex — рекурсивный
recursive_mutex rmtx;
rmtx.lock(); // Один поток может захватить несколько раз
rmtx.lock(); // OK (counter = 2)
rmtx.unlock(); // counter = 1
3. std::timed_mutex — с timeout
timed_mutex tmtx;
if (tmtx.try_lock_for(chrono::seconds(1))) {
tmtx.unlock(); // Захватил
} else {
cout << "Timeout" << endl;
}
4. std::shared_mutex — читатели/писатели
shared_mutex sm;
// Несколько читателей одновременно
shared_lock<shared_mutex> rlock(sm);
// Один писатель исключительно
unique_lock<shared_mutex> wlock(sm);
Как работает Mutex
- LOCKED — захвачен одним потоком
- UNLOCKED — свободен
- Попытка захватить LOCKED mutex → блокировка потока
- Освобождение → один из ждущих потоков просыпается
Правила использования
1. Защищай только критическую секцию
// Неправильно
lock_guard<mutex> guard(mtx);
long_computation(); // 100ms
counter++; // Только это нужно защищать
2. Минимальная критическая секция
long_computation();
{
lock_guard<mutex> guard(mtx);
counter++; // Только это
}
3. Избегай nested locks
// Опасно — deadlock риск!
mtx1.lock();
mtx2.lock();
Performance
Mutex замедляет из-за:
- Context switch потоков
- Синхронизации памяти между CPU ядрами
- Overhead lock/unlock операций
Поэтому держи критическую секцию максимально короткой.