Какие RAII-обертки для управления блокировками (Lock Guards) есть в стандартной библиотеке C++?

Ответ

Стандартная библиотека 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, и не парься. Главное — используй хоть что-то, а не голый мьютекс, а то будет вам хиросима и нигерсраки в коде.