Взаимные блокировки (deadlocks) возникают, когда два или более потока ожидают освобождения ресурсов, удерживаемых друг другом, что приводит к бесконечному ожиданию.
Вот несколько способов избежать взаимных блокировок в Python при работе с многопоточностью:
mutex_a
и mutex_b
), и потоки нуждаются в обоих, убедитесь, что все потоки сначала пытаются заблокировать mutex_a
, а затем mutex_b
. Если ресурс временно недоступен, поток должен освободить все полученные ресурсы и повторить попытку позже.
import threading
mutex_a = threading.Lock()
mutex_b = threading.Lock()
def thread_function(thread_id):
print(f"Поток {thread_id}: пытается получить mutex_a")
with mutex_a:
print(f"Поток {thread_id}: получил mutex_a")
print(f"Поток {thread_id}: пытается получить mutex_b")
with mutex_b:
print(f"Поток {thread_id}: получил mutex_b")
# Критическая секция, использующая оба ресурса
print(f"Поток {thread_id}: выполняет критическую секцию")
print(f"Поток {thread_id}: освободил mutex_b")
print(f"Поток {thread_id}: освободил mutex_a")
thread1 = threading.Thread(target=thread_function, args=(1,))
thread2 = threading.Thread(target=thread_function, args=(2,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
.acquire(timeout=...)
для блокировки с таймаутом.
import threading
import time
mutex_a = threading.Lock()
mutex_b = threading.Lock()
def thread_function(thread_id):
print(f"Поток {thread_id}: пытается получить mutex_a")
acquired_a = mutex_a.acquire(timeout=1) # Попытка получить блокировку с таймаутом в 1 секунду
if acquired_a:
try:
print(f"Поток {thread_id}: получил mutex_a")
print(f"Поток {thread_id}: пытается получить mutex_b")
acquired_b = mutex_b.acquire(timeout=1)
if acquired_b:
try:
print(f"Поток {thread_id}: получил mutex_b")
# Критическая секция
print(f"Поток {thread_id}: выполняет критическую секцию")
finally:
mutex_b.release()
print(f"Поток {thread_id}: освободил mutex_b")
else:
print(f"Поток {thread_id}: не смог получить mutex_b вовремя")
finally:
mutex_a.release()
print(f"Поток {thread_id}: освободил mutex_a")
else:
print(f"Поток {thread_id}: не смог получить mutex_a вовремя")
thread1 = threading.Thread(target=thread_function, args=(1,))
thread2 = threading.Thread(target=thread_function, args=(2,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
threading.Semaphore
) могут контролировать доступ к общему ресурсу, ограничивая количество потоков, которые могут одновременно получить доступ к ресурсу. Хотя семафоры сами по себе не предотвращают взаимные блокировки, они могут снизить вероятность их возникновения, уменьшая конкуренцию за ресурсы.
queue.Queue
) и пулы потоков (concurrent.futures.ThreadPoolExecutor
), которые могут упростить обработку параллельных задач и снизить потребность в явных блокировках, уменьшая риск взаимных блокировок.
Важно помнить, что предотвращение взаимных блокировок требует тщательного планирования и проектирования многопоточного кода. Нет универсального решения, и наилучший подход будет зависеть от конкретных требований вашего приложения.