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

Сколько мьютексов необходимо для Deadlock

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

Для возникновения deadlock (взаимной блокировки) необходимо как минимум два мьютекса. Deadlock происходит, когда два или более потока блокируют друг друга, ожидая освобождения ресурсов, которые удерживаются другими потоками.

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

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

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

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

  1. Взаимное исключение: Ресурсы не могут быть разделены, и каждый ресурс может быть занят только одним потоком в данный момент времени.
  2. Удержание и ожидание: Поток, который уже удерживает один ресурс, может запросить дополнительные ресурсы и ждать их освобождения.
  3. Отсутствие принудительного освобождения: Ресурсы не могут быть принудительно отобраны у потока, они могут быть освобождены только самим потоком.
  4. Циклическое ожидание: Существует замкнутый цикл потоков, где каждый поток ожидает ресурс, удерживаемый следующим в цикле потоком.

Пример с двумя мьютексами

Рассмотрим пример, где два потока используют два мьютекса, что может привести к deadlock:

#include <iostream>
#include <thread>
#include <mutex>
​
std::mutex mutex1;
std::mutex mutex2;
​
void thread1() {
    // Поток 1 блокирует первый мьютекс
    mutex1.lock();
    std::cout << "Thread 1 acquired mutex1" << std::endl;
​
    // Имитация работы
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
​
    // Поток 1 пытается заблокировать второй мьютекс
    mutex2.lock();
    std::cout << "Thread 1 acquired mutex2" << std::endl;
​
    // Освобождение мьютексов
    mutex2.unlock();
    mutex1.unlock();
}
​
void thread2() {
    // Поток 2 блокирует второй мьютекс
    mutex2.lock();
    std::cout << "Thread 2 acquired mutex2" << std::endl;
​
    // Имитация работы
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
​
    // Поток 2 пытается заблокировать первый мьютекс
    mutex1.lock();
    std::cout << "Thread 2 acquired mutex1" << std::endl;
​
    // Освобождение мьютексов
    mutex1.unlock();
    mutex2.unlock();
}
​
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(): Две функции, которые будут выполняться в отдельных потоках. Каждая из них пытается заблокировать оба мьютекса, но в разном порядке.
  • mutex1.lock(); и mutex2.lock();: Блокировка мьютексов. Поток 1 сначала блокирует mutex1, затем пытается заблокировать mutex2. Поток 2 делает наоборот.
  • std::this_thread::sleep_for(std::chrono::milliseconds(100));: Имитация работы, чтобы увеличить вероятность возникновения deadlock.
  • mutex1.unlock(); и mutex2.unlock();: Освобождение мьютексов после завершения работы.

Почему возникает Deadlock

В этом примере deadlock может возникнуть, если поток 1 заблокирует mutex1 и поток 2 заблокирует mutex2. Затем оба потока будут ждать освобождения мьютексов, которые удерживаются друг другом, что приведет к взаимной блокировке.

Как избежать Deadlock

Чтобы избежать deadlock, можно использовать следующие подходы:

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

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

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

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

Твои заметки