Какие виды мьютексов из стандартной библиотеки C++ знаешь?

«Какие виды мьютексов из стандартной библиотеки C++ знаешь?» — вопрос из категории Многопоточность, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В стандартной библиотеке C++ (начиная с C++11) определены следующие типы мьютексов, расположенные в заголовке <mutex>:

  1. std::mutex — фундаментальный, нерекурсивный мьютекс. Самый простой и быстрый. Не предоставляет рекурсивного захвата или таймаутов.

    #include <mutex>
    std::mutex resource_mutex;
    
    void access_resource() {
        // Всегда используем RAII для безопасности при исключениях
        std::lock_guard<std::mutex> guard(resource_mutex);
        // Критическая секция защищена
    }
  2. std::recursive_mutex — рекурсивный мьютекс. Полезен, когда функция, уже захватившая мьютекс, вызывает другую функцию, которой также нужен доступ к тому же защищённому ресурсу.

    std::recursive_mutex rec_mtx;
    void bar() {
        std::lock_guard<std::recursive_mutex> lock(rec_mtx);
        // ...
    }
    void foo() {
        std::lock_guard<std::recursive_mutex> lock(rec_mtx);
        bar(); // Без recursive_mutex здесь был бы deadlock
    }
  3. std::timed_mutex — мьютекс с поддержкой попытки захвата с таймаутом. Помимо обычных методов, предоставляет try_lock_for(duration) и try_lock_until(time_point).

    std::timed_mutex t_mutex;
    
    if (t_mutex.try_lock_for(std::chrono::seconds(1))) {
        // Успешный захват за 1 секунду
        t_mutex.unlock();
    } else {
        // Таймаут, выполняем fallback-логику
    }
  4. std::recursive_timed_mutex — объединяет возможности рекурсивного захвата и захвата с таймаутом.

Ключевая практика: Прямое использование методов lock() и unlock() подвержено ошибкам (например, забытый unlock при исключении). Поэтому стандартная библиотека предоставляет RAII-обёртки:

  • std::lock_guard — простая обёртка только для захвата и автоматического освобождения.
  • std::unique_lock — более гибкая обёртка, поддерживающая отложенный захват, таймауты и передачу владения блокировкой.