← Назад ко всем вопросам

Как и когда происходит Deadlock

1️⃣ Как кратко ответить

Deadlock происходит, когда два или более потока блокируют друг друга, ожидая освобождения ресурсов, которые удерживаются другими потоками. Это состояние возникает, когда выполняются четыре условия: взаимное исключение, удержание и ожидание, отсутствие принудительного освобождения и циклическое ожидание.

2️⃣ Подробное объяснение темы

Deadlock, или взаимная блокировка, — это состояние в многопоточных или многозадачных системах, когда два или более потока не могут продолжить выполнение, потому что каждый из них ожидает освобождения ресурса, удерживаемого другим потоком. Это может привести к остановке программы, так как ни один из потоков не может продолжить выполнение.

Условия возникновения Deadlock

Для возникновения deadlock должны выполняться следующие четыре условия одновременно:

  1. Взаимное исключение (Mutual Exclusion): Ресурсы не могут быть разделены; они могут быть заняты только одним потоком в данный момент времени.
  2. Удержание и ожидание (Hold and Wait): Поток, который уже удерживает один или несколько ресурсов, может запрашивать дополнительные ресурсы, удерживая при этом свои текущие.
  3. Отсутствие принудительного освобождения (No Preemption): Ресурсы не могут быть принудительно отобраны у потока; они могут быть освобождены только добровольно самим потоком.
  4. Циклическое ожидание (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

  1. Упорядочивание захвата ресурсов: Всегда захватывайте мьютексы в одном и том же порядке во всех потоках.
  2. Использование std::lock: Функция std::lock может захватить несколько мьютексов одновременно, предотвращая deadlock.
  3. Тайм-ауты и проверка состояния: Используйте std::try_lock для попытки захвата мьютекса с возможностью проверки состояния и тайм-аутами.

Deadlock — это критическая проблема в многопоточных приложениях, и понимание условий его возникновения помогает разработчикам разрабатывать более надежные и устойчивые к ошибкам программы.

Тема: Многопоточность / Синхронизация
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки