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.
1 Answer 1
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()
-
\$\begingroup\$ That's a great idea. Note that there should also be a
try/finally
around theno_we_cannot_fn()
. \$\endgroup\$Ron Klein– Ron Klein2014年01月20日 19:04:18 +00:00Commented Jan 20, 2014 at 19:04 -
\$\begingroup\$ @RonKlein In your version the
finally
block does nothing in the case whereno_we_cannot_fn()
gets called. \$\endgroup\$Janne Karila– Janne Karila2014年01月20日 19:09:24 +00:00Commented 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 atry
wrapper aroundno_we_cannot_fn()
in your suggestion. \$\endgroup\$Ron Klein– Ron Klein2014年01月20日 21:52:46 +00:00Commented Jan 20, 2014 at 21:52
Explore related questions
See similar questions with these tags.