Ответ
Стандартная библиотека C++ предоставляет несколько типов мьютексов, каждый для конкретных сценариев синхронизации:
-
std::mutex— базовый, нерекурсивный мьютекс. Если поток, уже владеющий им, попытается захватить его снова, это приведёт к неопределённому поведению (обычно к deadlock).std::mutex mtx; std::vector<int> shared_vec; void safe_push(int val) { std::lock_guard<std::mutex> lock(mtx); // RAII-захват shared_vec.push_back(val); } // Автоматическая разблокировка при выходе из области видимости -
std::recursive_mutex— рекурсивный мьютекс. Позволяет одному и тому же потоку захватывать его несколько раз. Необходимо вызватьunlock()столько же раз, сколько был вызванlock().std::recursive_mutex rec_mtx; void recursive_func(int x) { std::lock_guard<std::recursive_mutex> lock(rec_mtx); if (x > 0) { recursive_func(x - 1); // Безопасный рекурсивный вызов } } -
std::timed_mutex— расширяетstd::mutex, добавляя методыtry_lock_for()иtry_lock_until(), которые позволяют попытаться захватить мьютекс с таймаутом.std::timed_mutex tmtx; if (tmtx.try_lock_for(std::chrono::milliseconds(100))) { // Захватили за 100 мс tmtx.unlock(); } else { // Не удалось захватить, выполняем альтернативный код } -
std::recursive_timed_mutex— комбинация возможностей рекурсивного и timed мьютекса. -
std::shared_mutex(C++17) — мьютекс для реализации паттерна "множество читателей, один писатель". Позволяет нескольким потокам одновременно захватывать его в режиме разделяемой блокировки (lock_shared()) для чтения, но для записи требуется эксклюзивная блокировка (lock()).std::shared_mutex sh_mtx; std::string shared_data; // Поток-читатель { std::shared_lock lock(sh_mtx); // Разделяемая блокировка std::cout << shared_data; } // Поток-писатель { std::unique_lock lock(sh_mtx); // Эксклюзивная блокировка shared_data = "new value"; }
Рекомендация: Всегда предпочитайте RAII-обёртки (std::lock_guard, std::unique_lock, std::shared_lock) для управления блокировками, чтобы избежать утечки блокировок при исключениях.