Язык программирования Python

Тупиковая ситуация (deadlock)


Замки применяются для управления доступом к ресурсу, который нельзя использовать совместно. В программе таких ресурсов может быть несколько. При работе с замками важно хорошо продумать, не зайдет ли выполнение программы в тупик (deadlock) из-за того, что двум потокам потребуются одни и те же ресурсы, но ни тот, ни другой не смогут их получить, так как они уже получили замки. Такая ситуация проиллюстрирована в следующем примере:

import threading, time

resource = {'A': threading.Lock(), 'B': threading.Lock()}

def proc(n, rs): for r in rs: print "Процесс %s запрашивает ресурс %s" % (n, r) resource[r].acquire() print "Процесс %s получил ресурс %s" % (n, r) time.sleep(1) print "Процесс %s выполняется" % n for r in rs: resource[r].release() print "Процесс %s закончил выполнение" % n

p1 = threading.Thread(target=proc, name="t1", args=["1", "AB"]) p2 = threading.Thread(target=proc, name="t2", args=["2", "BA"]) p1.start() p2.start() p1.join() p2.join()

В этом примере два потока (t1 и t2) запрашивают замки к одним и тем же ресурсам (A и B), но в разном порядке, отчего получается, что ни у того, ни у другого не хватает ресурсов для дальнейшей работы, и они оба безнадежно повисают, ожидая освобождения нужного ресурса. Благодаря операторам print можно увидеть последовательность событий:

Процесс 1 запрашивает ресурс A Процесс 1 получил ресурс A Процесс 2 запрашивает ресурс B Процесс 2 получил ресурс B Процесс 1 запрашивает ресурс B Процесс 2 запрашивает ресурс A

Существуют методики, позволяющие избежать подобных тупиков, однако их рассмотрение не входит в рамки данной лекции. Можно посоветовать следующие приемы:

  • построить логику приложения так, чтобы никогда не запрашивать замки к двум ресурсам сразу. Возможно, придется определить составной ресурс. В частности, к данному примеру можно было бы определить замок "AB" для указания эксклюзивного доступа к ресурсам A и B.
  • строго упорядочить все ресурсы (например, по цене) и всегда запрашивать их в определенном порядке (скажем, начиная с более дорогих ресурсов). При этом перед заказом некоторого ресурса поток должен отказаться от заблокированных им более дешевых ресурсов.



Содержание раздела