def locked(*args, **kwargs):
"""A locking **method** decorator.
It will look for a provided attribute (typically a lock or a list
of locks) on the first argument of the function decorated (typically this
is the 'self' object) and before executing the decorated function it
activates the given lock or list of locks as a context manager,
automatically releasing that lock on exit.
NOTE(harlowja): if no attribute name is provided then by default the
attribute named '_lock' is looked for (this attribute is expected to be
the lock/list of locks object/s) in the instance object this decorator
is attached to.
NOTE(harlowja): a custom logger (which will be used if lock release
failures happen) can be provided by passing a logger instance for keyword
argument ``logger``.
"""
def decorator(f):
attr_name = kwargs.get('lock', '_lock')
logger = kwargs.get('logger')
@six.wraps(f)
def wrapper(self, *args, **kwargs):
attr_value = getattr(self, attr_name)
if isinstance(attr_value, (tuple, list)):
with _utils.LockStack(logger=logger) as stack:
for i, lock in enumerate(attr_value):
if not stack.acquire_lock(lock):
raise threading.ThreadError("Unable to acquire"
" lock %s" % (i + 1))
return f(self, *args, **kwargs)
else:
lock = attr_value
with lock:
return f(self, *args, **kwargs)
return wrapper
# This is needed to handle when the decorator has args or the decorator
# doesn't have args, python is rather weird here...
if kwargs or not args:
return decorator
else:
if len(args) == 1:
return decorator(args[0])
else:
return decorator
评论列表
文章目录