Ответ
В стандартной библиотеке C++ (начиная с C++11) определены следующие типы мьютексов, расположенные в заголовке <mutex>:
-
std::mutex— фундаментальный, нерекурсивный мьютекс. Самый простой и быстрый. Не предоставляет рекурсивного захвата или таймаутов.#include <mutex> std::mutex resource_mutex; void access_resource() { // Всегда используем RAII для безопасности при исключениях std::lock_guard<std::mutex> guard(resource_mutex); // Критическая секция защищена } -
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 } -
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-логику } -
std::recursive_timed_mutex— объединяет возможности рекурсивного захвата и захвата с таймаутом.
Ключевая практика: Прямое использование методов lock() и unlock() подвержено ошибкам (например, забытый unlock при исключении). Поэтому стандартная библиотека предоставляет RAII-обёртки:
std::lock_guard— простая обёртка только для захвата и автоматического освобождения.std::unique_lock— более гибкая обёртка, поддерживающая отложенный захват, таймауты и передачу владения блокировкой.