4
\$\begingroup\$

I wrote a simple class in Python, which controls code invocation, in a multi-threaded environment, with the following logic:

The class' main method, named try_to_do, takes two function pointers as arguments: yes_we_can_fn and no_we_cannot_fn.

In any point in time, only a single thread can invoke code the function passed as yes_we_can_fn argument.

If a specific thread tries to invoke its code, but some other thread is already invoking its code, then the no_we_cannot_fn is invoked instead of yes_we_can_fn.

If there's an exception in the code being executed, it should raise to the calling context.

The code:

from threading import Lock
class MyController():
 def __init__(self):
 self.locker = Lock()
 self.is_active = False
 def try_to_do(self, yes_we_can_fn, no_we_cannot_fn):
 with self.locker:
 if self.is_active:
 we_can_do_it = False
 else:
 we_can_do_it = True
 self.is_active = True
 try:
 if we_can_do_it:
 yes_we_can_fn()
 else:
 no_we_cannot_fn()
 finally:
 if we_can_do_it:
 with self.locker:
 self.is_active = False

Usage:

ctl = MyController()
def p1():
 from time import sleep
 print 'before sleep'
 sleep(2)
 print 'done'
def p2():
 print 'too busy, will try some other time'
ctl.try_to_do(p1, p2)

I'd like to get some reviews: thread safety (maybe I'm missing something?), coding style, etc.

asked Jan 20, 2014 at 10:17
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

You could avoid the is_active variable by using the lock in a non-blocking manner:

def try_to_do(self, yes_we_can_fn, no_we_cannot_fn):
 if self.locker.acquire(False):
 try:
 yes_we_can_fn()
 finally:
 self.locker.release()
 else:
 no_we_cannot_fn()
answered Jan 20, 2014 at 14:40
\$\endgroup\$
3
  • \$\begingroup\$ That's a great idea. Note that there should also be a try/finally around the no_we_cannot_fn(). \$\endgroup\$ Commented Jan 20, 2014 at 19:04
  • \$\begingroup\$ @RonKlein In your version the finally block does nothing in the case where no_we_cannot_fn() gets called. \$\endgroup\$ Commented Jan 20, 2014 at 19:09
  • \$\begingroup\$ After another look in your suggested code, I see that even if there was as exception while invoking no_we_cannot_fn, the class' state won't get affected. In my (original) code, it would be. So you're absolutely right, there's no need for a try wrapper around no_we_cannot_fn() in your suggestion. \$\endgroup\$ Commented Jan 20, 2014 at 21:52

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.