Ответ
Стандартная библиотека 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 для простых случаев.
Ответ 18+ 🔞
Давай разберём эту тему, а то народ путается, как последний пидарас шерстяной. Смотри, в C++ есть три основных способа не обосраться с мьютексами, чтобы твой код не накрылся медным тазом от дедлоков.
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`, но для толпы.** Создан, чтобы захватывать кучу мьютексов разом и без дедлоков.
* **Использует `std::lock` внутри,** так что про взаимные блокировки можешь забыть, как про страшный сон.
* Если мьютексов больше одного — это твой выбор, ядрёна вошь.
```cpp
std::mutex mtx1, mtx2, mtx3;
{
// Хуяк — и все три мьютекса твои. Атомарно и безопасно.
std::scoped_lock lock_all(mtx1, mtx2, mtx3);
// Работай со всеми ресурсами сразу, как царь горы
} // Все отпускаются в правильном порядке, волнение ебать.
| Короче, сводная таблица, чтобы не ебать себе мозг: | Штука | Много мьютексов | Захват потом | Попытка захвата | Ручное управление |
|---|---|---|---|---|---|
lock_guard |
❌ | ❌ | ❌ | ❌ | |
unique_lock |
❌ | ✅ | ✅ | ✅ | |
scoped_lock |
✅ | ❌ | ❌ | ❌ |
Что брать? Всё просто, чувак. Несколько мьютексов — scoped_lock. Нужна магия с таймаутами или условными переменными — unique_lock. Всё остальное, 95% случаев — lock_guard, и не парься. Главное — используй хоть что-то, а не голый мьютекс, а то будет вам хиросима и нигерсраки в коде.