Ответ
Для классического взаимоблокирования (deadlock) необходимо как минимум два мьютекса. Ключевое условие — потоки захватывают их в разном порядке.
Пример на C++:
#include <thread>
#include <mutex>
std::mutex mtx1;
std::mutex mtx2;
void thread_a_work() {
std::lock_guard<std::mutex> lock1(mtx1); // Захват первого
// Имитация работы, во время которой нужен второй ресурс
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lock2(mtx2); // Ожидание второго (заблокирован thread_b)
// Критическая секция
}
void thread_b_work() {
std::lock_guard<std::mutex> lock2(mtx2); // Захват второго
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lock1(mtx1); // Ожидание первого (заблокирован thread_a)
// Критическая секция
}
int main() {
std::thread t1(thread_a_work);
std::thread t2(thread_b_work);
t1.join();
t2.join(); // Программа может зависнуть здесь из-за deadlock
return 0;
}
Как я избегаю этого:
- Всегда захватываю мьютексы в строго одинаковом порядке во всех потоках.
- Использую
std::lock()илиstd::scoped_lock(C++17) для атомарного захвата нескольких мьютексов, что исключает deadlock.// Безопасный захват std::scoped_lock lock_all(mtx1, mtx2);