8
\$\begingroup\$

I needed to impose on a Python method the following locking semantics: the method can only be run by one thread at a time. If thread B tries to run the method while it is already being run by thread A, then thread B immediately receives a return value of None.

I wrote the following decorator to apply these semantics:

from threading import Lock
def non_blocking_lock(fn):
 fn.lock = Lock()
 @wraps(fn)
 def locker(*args, **kwargs):
 if fn.lock.acquire(False):
 try:
 return fn(*args, **kwargs)
 finally:
 fn.lock.release()
 return locker

This works in my testing so far. Does anyone notice any gotchas or have any suggestions for improvements?

Revised version

After the suggestions by @RemcoGerlich, I have added a docstring and kept the lock local to the decorator:

from threading import Lock
def non_blocking_lock(fn):
 """Decorator. Prevents the function from being called multiple times simultaneously.
 If thread A is executing the function and thread B attempts to call the
 function, thread B will immediately receive a return value of None instead.
 """
 lock = Lock()
 @wraps(fn)
 def locker(*args, **kwargs):
 if lock.acquire(False):
 try:
 return fn(*args, **kwargs)
 finally:
 lock.release()
 return locker
asked Feb 25, 2014 at 19:52
\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

I think this will work fine and it's very close to how I would write it myself.

A few small things come to mind:

  • There's no documentation of any kind that explains what the semantics are, and they're not explicit either (the return None if the lock isn't acquired is entirely implicit). I would put the short explanation you put in this question into a docstring, and/or add an explicit else: return None to the if statement.

  • is there any reason why the lock object is exposed to the outside world by making it a property of the function (fn.lock) ? I would simply make it a local variable, so that it's hidden. But I'm not sure.

answered Feb 25, 2014 at 20:32
\$\endgroup\$
1
  • \$\begingroup\$ Thank you for your feedback! I’ve amended my original code and added it to the question, for posterity. \$\endgroup\$ Commented Feb 26, 2014 at 14:49

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.