Ответ
Deadlock (взаимная блокировка) — это ситуация в многопоточных или многопроцессных системах, когда два или более потока/процесса бесконечно ожидают ресурсы, захваченные друг другом, и ни один из них не может продолжить выполнение. Это приводит к зависанию системы или ее части.
Пример Deadlock на Python с использованием threading
:
import threading
import time
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread1_func():
print("Thread 1: Попытка захватить lock1...")
with lock1:
print("Thread 1: lock1 захвачен. Попытка захватить lock2...")
time.sleep(0.1) # Даем время другому потоку захватить lock2
with lock2:
print("Thread 1: lock2 захвачен.")
print("Thread 1: Ресурсы освобождены.")
def thread2_func():
print("Thread 2: Попытка захватить lock2...")
with lock2:
print("Thread 2: lock2 захвачен. Попытка захватить lock1...")
time.sleep(0.1) # Даем время другому потоку захватить lock1
with lock1:
print("Thread 2: lock1 захвачен.")
print("Thread 2: Ресурсы освобождены.")
t1 = threading.Thread(target=thread1_func)
t2 = threading.Thread(target=thread2_func)
t1.start()
t2.start()
t1.join()
t2.join()
print("Программа завершена (если не было deadlock).")
В этом примере thread1_func
пытается захватить lock1
, затем lock2
. thread2_func
пытается захватить lock2
, затем lock1
. Если оба потока одновременно захватят свои первые блокировки, они будут бесконечно ждать друг друга, что приведет к deadlock.
Условия возникновения Deadlock (условия Коффмана): Deadlock возникает, если одновременно выполняются все четыре условия:
- Взаимное исключение (Mutual Exclusion): Ресурсы не могут быть разделены; только один поток может использовать ресурс в данный момент.
- Удержание и ожидание (Hold and Wait): Поток, удерживающий один или несколько ресурсов, ожидает захвата дополнительных ресурсов, которые в данный момент удерживаются другими потоками.
- Отсутствие вытеснения (No Preemption): Ресурсы не могут быть принудительно отобраны у потока; они могут быть освобождены только самим потоком, который их удерживает.
- Круговое ожидание (Circular Wait): Существует циклическая цепочка потоков, где каждый поток в цепочке ожидает ресурс, удерживаемый следующим потоком в этой цепочке.
Стратегии предотвращения и разрешения Deadlock:
- Предотвращение: Нарушение одного или нескольких условий Коффмана.
- Упорядочивание блокировок: Всегда захватывать ресурсы в заранее определенном порядке (например,
lock1
передlock2
). Это нарушает условие кругового ожидания. - Захват всех ресурсов сразу: Поток запрашивает все необходимые ресурсы одновременно. Если какой-либо ресурс недоступен, он не захватывает ни одного и ждет. Нарушает условие удержания и ожидания.
- Упорядочивание блокировок: Всегда захватывать ресурсы в заранее определенном порядке (например,
- Избегание: Динамическое принятие решений о выделении ресурсов (например, алгоритм банкира), чтобы избежать небезопасных состояний.
- Обнаружение и восстановление: Позволяет deadlock произойти, затем обнаруживает его и восстанавливается (например, путем прерывания одного или нескольких потоков).
- Использование таймаутов: При попытке захвата блокировки устанавливается таймаут (
lock.acquire(timeout=5)
). Если блокировка не получена за это время, поток может освободить уже захваченные ресурсы и повторить попытку.