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

Сколько нужно Mutex, чтобы создать Deadlock

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

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

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

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

Пример с двумя mutex

Рассмотрим пример, где два потока используют два mutex для синхронизации доступа к ресурсам:

#include <iostream>
#include <thread>
#include <mutex>
​
std::mutex mutex1;
std::mutex mutex2;
​
void thread1() {
    // Поток 1 блокирует первый mutex
    mutex1.lock();
    std::cout << "Thread 1: locked mutex1" << std::endl;
​
    // Имитация работы
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
​
    // Поток 1 пытается заблокировать второй mutex
    mutex2.lock();
    std::cout << "Thread 1: locked mutex2" << std::endl;
​
    // Освобождение ресурсов
    mutex2.unlock();
    mutex1.unlock();
}
​
void thread2() {
    // Поток 2 блокирует второй mutex
    mutex2.lock();
    std::cout << "Thread 2: locked mutex2" << std::endl;
​
    // Имитация работы
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
​
    // Поток 2 пытается заблокировать первый mutex
    mutex1.lock();
    std::cout << "Thread 2: locked mutex1" << std::endl;
​
    // Освобождение ресурсов
    mutex1.unlock();
    mutex2.unlock();
}
​
int main() {
    std::thread t1(thread1);
    std::thread t2(thread2);
​
    t1.join();
    t2.join();
​
    return 0;
}

Объяснение кода

  1. Создание двух mutex: std::mutex mutex1; и std::mutex mutex2; — это объекты синхронизации, которые используются для управления доступом к общим ресурсам.

  2. Функция thread1:

    • Блокирует mutex1 с помощью mutex1.lock();.
    • Выводит сообщение о блокировке mutex1.
    • Имитация работы с помощью std::this_thread::sleep_for.
    • Пытается заблокировать mutex2 с помощью mutex2.lock();.
    • Выводит сообщение о блокировке mutex2.
    • Освобождает оба mutex с помощью unlock().
  3. Функция thread2:

    • Блокирует mutex2 с помощью mutex2.lock();.
    • Выводит сообщение о блокировке mutex2.
    • Имитация работы с помощью std::this_thread::sleep_for.
    • Пытается заблокировать mutex1 с помощью mutex1.lock();.
    • Выводит сообщение о блокировке mutex1.
    • Освобождает оба mutex с помощью unlock().
  4. Функция main:

    • Создает два потока t1 и t2, которые выполняют функции thread1 и thread2.
    • Ожидает завершения потоков с помощью join().

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

В этом примере deadlock возникает, потому что:

  • Поток 1 блокирует mutex1 и ожидает mutex2.
  • Поток 2 блокирует mutex2 и ожидает mutex1.

Оба потока ждут друг друга, и ни один из них не может продолжить выполнение. Это классический пример deadlock, который может быть решен путем изменения порядка блокировки mutex или использования других механизмов синхронизации, таких как std::lock или std::scoped_lock, которые предотвращают взаимные блокировки.

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

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

Твои заметки