Ответ
Стандартная библиотека C++ предоставляет три основные RAII-обертки для безопасного управления мьютексами.
1. std::lock_guard (C++11) - базовая обертка:
- Простая и эффективная. При создании сразу захватывает мьютекс, при разрушении - освобождает.
- Нельзя разблокировать досрочно или передавать владение.
- Идеален для большинства критических секций.
std::mutex mtx; { std::lock_guard<std::mutex> lock(mtx); // Захват здесь // Критическая секция защищена } // Автоматическое освобождение при выходе из области видимости
2. std::unique_lock (C++11) - гибкая обертка:
- Предоставляет расширенный контроль. Поддерживает отложенную блокировку, попытки захвата, повторную блокировку и передачу владения.
- Имеет небольшие накладные расходы по сравнению с
lock_guard.std::mutex mtx; std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // Создаем, но не захватываем
// Захватываем позже, возможно, с таймаутом или попыткой if (lock.try_lock_for(std::chrono::milliseconds(100))) { // Работа в критической секции lock.unlock(); // Можно освободить досрочно // ... какая-то не защищенная работа lock.lock(); // И захватить снова } // Все еще автоматически освобождается при разрушении
**3. `std::scoped_lock` (C++17) - для нескольких мьютексов:**
* **Аналог `lock_guard` для множественной блокировки.**
* **Гарантирует deadlock-free захват** нескольких мьютексов с помощью алгоритма `std::lock`.
* Предпочтительнее `std::lock_guard` при работе с более чем одним мьютексом.
```cpp
std::mutex mtx1, mtx2, mtx3;
{
// Захватывает все три мьютекса атомарно, избегая deadlock.
std::scoped_lock lock_all(mtx1, mtx2, mtx3);
// Критическая секция, использующая все три ресурса
} // Все мьютексы освобождаются в обратном порядке
| Краткое сравнение: | Обертка | Множественные мьютексы | Отложенный захват | Попытка захвата | Ручное управление |
|---|---|---|---|---|---|
lock_guard |
❌ | ❌ | ❌ | ❌ | |
unique_lock |
❌ | ✅ | ✅ | ✅ | |
scoped_lock |
✅ | ❌ | ❌ | ❌ |
Выбор: Используйте scoped_lock для нескольких мьютексов, unique_lock когда нужна гибкость (условные переменные, таймауты), и lock_guard для простых случаев.