import threading rlck = threading.RLock()
Класс RLock()
модуля threading
реализует объекты реентерабельной (повторной) блокировки.
Повторяющаяся блокировка должна быть снята потоком, который ее получил. Как только поток получил повторную блокировку, тот же поток может получить ее снова без блокировки. Поток должен освобождать ее столько раз, сколько раз он ее приобрел.
Обратите внимание, что threading.RLock
на самом деле является фабричным классом, который возвращает экземпляр наиболее эффективной версии конкретного класса threading.RLock
, поддерживаемого платформой.
Повторная блокировка потока - это примитив синхронизации, который может быть получен несколько раз одним и тем же потоком. Внутри он использует концепции "владеющего потоком" и "уровня рекурсии" в дополнение к locked
/unlocked
состоянию, используемому примитивными блокировками threading.Lock
. В заблокированном locked
состоянии какой-то поток владеет блокировкой, в разблокированном unlocked
состоянии ни один поток не владеет им.
Чтобы включить блокировку, поток вызывает свой метод RLock.acquire()
, он возвращает результат своему экземпляру, когда поток владеет блокировкой. Чтобы снять блокировку, поток вызывает свой метод RLock.release()
.
Пары вызовов RLock.acquire()
/RLock.release()
могут быть вложенными, только последний RLock.release()
(release()
самой внешней пары) сбрасывает режим locked
на unlocked
и позволяет продолжить работу другому потоку, заблокированному в RLock.acquire()
.
Класс threading.RLock()
также поддерживают протокол управления контекстом.
threading.RLock
.RLock.acquire()
устанавливает блокировку,RLock.release()
снимает блокировку,threading.RLock()
,RLock.acquire(blocking=True, timeout=-1)
:Метод RLock.acquire()
устанавливает блокировку, блокирующую или неблокирующую..
При вызове без аргументов:
При вызове метода с параметром blocking
, установленным в значение True
, выполнит то же действие, что и при вызове без аргументов и возвратит значение True
.
При вызове метода с аргументом blocking
, установленным в False
, не ставит блокировку, а проверит, сможет ли метод с blocking=True
поставить блокировку, если нет, то немедленно вернет False
, в противном случае установит блокировку и возвратит True
.
При вызове с аргументом тайм-аута timeout
с числом float
, установленным в положительное значение, будет блокировать выполнение кода не более чем на количество секунд, заданное таймаутом и до тех пор, пока блокировка не будет получена. В этом случае, возвращает True
, если блокировка была получена и False
, если истекло время ожидания timeout
.
RLock.release()
:Метод RLock.release()
снимает блокировку, уменьшив уровень рекурсии. Если после декремента он равен нулю, то сбрасывает блокировку на unlocked
(т.е. блокировка не принадлежащую ни одному потоку), и если какие-либо другие потоки заблокированы, ожидая разблокировки, то разрешит выполнение ровно одному из них. Если после декремента уровень рекурсии все еще отличен от нуля, то блокировка остается locked
и принадлежит вызывающему потоку.
Вызывайте этот метод только тогда, когда вызывающий поток владеет блокировкой. Если этот метод вызывается при уже снятой блокировке, то возникает исключение RuntimeError
Возвращаемого значения нет.
threading.RLock()
.Объекты threading.Lock()
не могут быть получены более одного раза, даже одним и тем же потоком. Это может привести к нежелательным побочным эффектам, если доступ к блокировке осуществляется более чем одной функцией в одной цепочке вызовов.
В этом случае второму вызову Lock.acquire()
необходимо дать нулевой тайм-аут, чтобы предотвратить его блокировку, потому что блокировка была уже получена первым вызовом.
>>> import threading >>> lock = threading.Lock() >>> lock # <unlocked _thread.lock object at 0x7f836cdb0b48> # первая блокировка >>> 'First try :', lock.acquire() # ('First try :', True) >>> lock # <locked _thread.lock object at 0x7f836cdb0b48> # вторая блокировка 'Second try:', lock.acquire(timeout=0) # ('Second try:', False)
В ситуации, когда отдельный код из одного и того же потока должен “повторно получить” блокировку, необходимо использовать объекты threading.RLock
.
Единственным изменением в коде из предыдущего примера была замена объекта Rlock на Lock.
>>> import threading >>> rlock = threading.RLock() # первая блокировка >>> 'First try :', rlock.acquire() # ('First try :', True) # вторая блокировка >>>'Second try:', rlock.acquire(timeout=0) # ('Second try:', True) # смотрим состояние - счетчик повторных блокировок count=2 >>> rlock # <locked _thread.RLock object owner=140202475812672 count=2 at 0x7f83693acb10> # разблокируем 2 раза >>> rlock.release() >>> rlock.release() # смотрим состояние - счетчик повторных блокировок count=0 >>> rlock # <locked _thread.RLock object owner=140202475812672 count=0 at 0x7f83693acb10> # пробуем разблокировать уже разблокированное состояние >>> rlock.release() # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # RuntimeError: cannot release un-acquired lock