You can write a decorator that locks decorated methods with a given lock.
from functools import wraps
from threading import RLock
def synchronized():
lock = RLock()
def wrapper(f):
@wraps(f)
def inner_wrapper(*args, **kwargs):
with lock:
return f(*args, **kwargs)
return inner_wrapper
return wrapper
synchronizer = synchronized()
class Library:
@synchronizer
def __init__(self):
pass
@synchronizer
def method1(self):
pass
@synchronizer
def method2(self):
pass
However, this requires you to decorate each method. Here I wrote a mixin with __init_subclass__
that does that automatically.
class Synchronized:
def __init_subclass__(cls, **kwargs):
synchronizer = synchronized()
for name in cls.__dict__:
attr = getattr(cls, name)
if callable(attr):
setattr(cls, name, synchronized(attr))
Notice I used a RLock
instead of a Lock
. A RLock
, or reentrant lock, allows the lock to be acquired multiple times by the same thread. This allows methods to call one another in the same thread.
Usage
class Library(Synchronized):
def __init__(self):
pass
def method1(self):
pass
def method2(self):
pass