Как и когда происходит Deadlock
1️⃣ Как кратко ответить
Deadlock происходит, когда два или более потока блокируют друг друга, ожидая освобождения ресурсов, которые удерживаются другими потоками. Это состояние возникает, когда выполняются четыре условия: взаимное исключение, удержание и ожидание, отсутствие принудительного освобождения и циклическое ожидание.
2️⃣ Подробное объяснение темы
Deadlock, или взаимная блокировка, — это состояние в многопоточных или многозадачных системах, когда два или более потока не могут продолжить выполнение, потому что каждый из них ожидает освобождения ресурса, удерживаемого другим потоком. Это может привести к остановке программы, так как ни один из потоков не может продолжить выполнение.
Условия возникновения Deadlock
Для возникновения deadlock должны выполняться следующие четыре условия одновременно:
- Взаимное исключение (Mutual Exclusion): Ресурсы не могут быть разделены; они могут быть заняты только одним потоком в данный момент времени.
- Удержание и ожидание (Hold and Wait): Поток, который уже удерживает один или несколько ресурсов, может запрашивать дополнительные ресурсы, удерживая при этом свои текущие.
- Отсутствие принудительного освобождения (No Preemption): Ресурсы не могут быть принудительно отобраны у потока; они могут быть освобождены только добровольно самим потоком.
- Циклическое ожидание (Circular Wait): Существует замкнутый цикл потоков, где каждый поток ожидает ресурс, удерживаемый следующим в цепочке потоком.
Пример Deadlock в C++
Рассмотрим пример на C++, где два потока пытаются захватить два мьютекса в разном порядке, что может привести к deadlock.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mutex1;
std::mutex mutex2;
void Thread1() {
// Поток 1 захватывает первый мьютекс
std::lock_guard<std::mutex> lock1(mutex1);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Имитируем работу
// Поток 1 пытается захватить второй мьютекс
std::lock_guard<std::mutex> lock2(mutex2);
std::cout << "Thread 1 has locked both mutexes" << std::endl;
}
void Thread2() {
// Поток 2 захватывает второй мьютекс
std::lock_guard<std::mutex> lock1(mutex2);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Имитируем работу
// Поток 2 пытается захватить первый мьютекс
std::lock_guard<std::mutex> lock2(mutex1);
std::cout << "Thread 2 has locked both mutexes" << std::endl;
}
int main() {
// Создаем два потока
std::thread t1(Thread1);
std::thread t2(Thread2);
// Ожидаем завершения потоков
t1.join();
t2.join();
return 0;
}
Объяснение кода
std::mutex mutex1;иstd::mutex mutex2;: Объявление двух мьютексов, которые будут использоваться для синхронизации потоков.void Thread1()иvoid Thread2(): Две функции, которые будут выполняться в отдельных потоках. Каждая из них пытается захватить оба мьютекса, но в разном порядке.std::lock_guard<std::mutex> lock1(mutex1);: Поток 1 захватываетmutex1.std::lock_guardавтоматически освобождает мьютекс при выходе из области видимости.std::this_thread::sleep_for(std::chrono::milliseconds(100));: Имитирует задержку, чтобы увеличить вероятность возникновения deadlock.std::lock_guard<std::mutex> lock2(mutex2);: Поток 1 пытается захватитьmutex2, который может быть уже захвачен Потоком 2.std::thread t1(Thread1);иstd::thread t2(Thread2);: Создание двух потоков, которые выполняют функцииThread1иThread2.t1.join();иt2.join();: Ожидание завершения обоих потоков.
Как избежать Deadlock
- Упорядочивание захвата ресурсов: Всегда захватывайте мьютексы в одном и том же порядке во всех потоках.
- Использование
std::lock: Функцияstd::lockможет захватить несколько мьютексов одновременно, предотвращая deadlock. - Тайм-ауты и проверка состояния: Используйте
std::try_lockдля попытки захвата мьютекса с возможностью проверки состояния и тайм-аутами.
Deadlock — это критическая проблема в многопоточных приложениях, и понимание условий его возникновения помогает разработчикам разрабатывать более надежные и устойчивые к ошибкам программы.
🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!
Подписаться