How would you go about combining threading.RLock
with threading.Semaphore
? Or does such a structure already exist?
In Python, there is a primitive for a Reentrant lock, threading.RLock(N)
, which allows the same thread to acquire a lock multiple times, but no other threads can. There is also threading.Semaphore(N)
, which allows the lock to be acquired N
times before blocking. How would one combine these two structures? I want up to N
separate threads to be able to acquire the lock, but I'd like each individual lock on a thread to be a reentrant one.
So I guess a Reentrant semaphore does not exist. Here is the implementation I came up with, happy to entertain comments.
import threading
import datetime
class ReentrantSemaphore(object):
'''A counting Semaphore which allows threads to reenter.'''
def __init__(self, value = 1):
self.local = threading.local()
self.sem = threading.Semaphore(value)
def acquire(self):
if not getattr(self.local, 'lock_level', 0):
# We do not yet have the lock, acquire it.
start = datetime.datetime.utcnow()
self.sem.acquire()
end = datetime.datetime.utcnow()
if end - start > datetime.timedelta(seconds = 3):
logging.info("Took %d Sec to lock."%((end - start).total_seconds()))
self.local.lock_time = end
self.local.lock_level = 1
else:
# We already have the lock, just increment it due to the recursive call.
self.local.lock_level += 1
def release(self):
if getattr(self.local, 'lock_level', 0) < 1:
raise Exception("Trying to release a released lock.")
self.local.lock_level -= 1
if self.local.lock_level == 0:
self.sem.release()
__enter__ = acquire
def __exit__(self, t, v, tb):
self.release()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With