Lock acquisition by the same thread - deadlock protection
Dieter Maurer
dieter at handshake.de
Sun Mar 15 06:32:43 EDT 2020
Cameron Simpson wrote at 2020-3-15 10:17 +1100:
>On 12Mar2020 20:08, Dieter Maurer <dieter at handshake.de> wrote:
> ...
>>The documentation for the basic lock explicitely allows
>>lock release by a foreign thread.
>>As I understand the documentation, this lock type is by design
>>very basic - a mechanism to implement higher level abstractions.
>>I use other synchronisation mechanisms when the basic lock does
>>not fit my requirements.
>
>Aye. I have certainly gone:
>- take lock associated with some task specific resource
>- set up task
>- kick off worker Thread (or queue worker function for later)
>- worker releases the lock
>
>However, having an error check mode disallowing attempts by the same
>Thread to take a Lock it itself took seems valuable. If the lock object
>has that piece of information (IIRC it does).
Below is a Python 3 implementation for such a lock.
The quirks required to get a nested "with" safe might be seen
as an indication that it should not be implemented in the base lock
class.
from _thread import allocate_lock, get_ident
class NestedTLockError(RuntimeError):
"""Special error used to make nested ``with`` statements safe."""
def __init__(self, message, lock):
self._lock = lock
super().__init__(message, lock)
class TLock:
"""A lock preventing the same thread to get the lock twice."""
def __init__(self):
self._lock = allocate_lock()
self._tid = None
def acquire(self, wait=True, timeout=-1):
tid = get_ident()
if self._tid == tid:
# this remains stable
raise NestedTLockError("already acquired", self)
acquired = self._lock.acquire(0) or self._lock.acquire(wait, timeout)
if acquired:
# Lock successfully acquired - no other thread will interfere
self._tid = tid
return acquired
def __enter__(self):
return self.acquire()
def release(self):
# the application is responsible that nothing interferes
# with our release
self._tid = None
self._lock.release()
def __exit__(self, t, v, tb):
if not self.locked(): return # the ``__enter__`` failed
if t is NestedTLockError and v._lock is self:
# the ``__enter__`` failed due to nested lock acquisition
# we must not release the lock (it would be too early)
# but must allow the outer ``__exit__`` to release the lock
v._lock = None
return
self.release()
def locked(self): return self._lock.locked()
More information about the Python-list
mailing list