With-statement And Threading :making Function Execute Before Run
Solution 1:
The problem here is that you want the run
function to wait until the execute
function is called.
Of course the obvious solution is to call execute
before you call start
:
t1.execute(print_time,5,1)
t2.execute(print_time,5,2)
with contextlib.nested(t1, t2):
pass
… or just make execute
call start
, or pass the function in to the constructor or the start
call, or…
Also, your intended design is a bit weird. The thread function is designed to handle the case where _f
hasn't been set… but you want it to wait until _f
has been set?
But it's conceivable that this kind of problem could come up in a more realistic design, so, let's look at how to solve it.
First, adding sleep
to solve a threading problem is almost always a sign that you're doing something very wrong. It's also a great way to cause either horrible performance problems (as in: by the time you add enough sleep
s in enough places to make everything mostly work, it takes 30 seconds for your app to start instead of 30 milliseconds)—and, worse, race-condition bugs (surely 1 second is always enough time, right? unless the computer is thrashing swap, or waking up from hibernate, or busy with other programs using all the CPU, or…).
If you're trying to synchronize actions across threads, you need to use a synchronization object. The trick is knowing the right one. Read the docs for Lock
through Event
(and 3.x adds Barrier
), and find a tutorial on threading in general to get a broader idea of what all of these things are for.*
In this case, you've got code that's waiting for some change to saved state, and other code that's making the change, which is the prototypical use case for a 'Condition'. So:
classMythread(threading.Thread):def__init__(self, threadID, name, condition):
self.condition = condition
# ... same as beforedefrun(self):
# ... setup before checking for _f
with self.condition:whilenotself._f:self.condition.wait()
self._f()
# ... anything else you want
Now, you need to create the Condition
, pass it to the threads, and notify
it.
You could use a single Condition
:
condition= threading.Condition()
t1 = Mythread(1, "Thread1", condition)
t2 = Mythread(2, "Thread2", condition)
with contextlib.nested(t1,t2):
withcondition:
t1.execute(print_time, 5, 1)
t2.execute(print_time, 5, 2)
condition.notify_all()
Alternatively, you can give each thread its own Condition
:
class Mythread(threading.Thread):
def __init__(self, threadID, name):
self.condition = Condition()
# ... same as before
# ...
t1 = Mythread(1, "Thread1")
t2 = Mythread(2, "Thread2")
with contextlib.nested(t1,t2):
with t1.condition:
t1.execute(print_time, 5, 1)
t1.condition.notify()
with t2.condition:
t2.execute(print_time, 5, 1)
t2.condition.notify()
Note that this doesn't allow you to explicit "not set" _f
, but it's pretty easy to do that. For example, you can add an _f_set
attribute, and check that instead of _f
, so someone can call execute(None)
(and then notify
) to wake you up and get you to the "no _f
" case.
* Warning: Some of the naming is inconsistent. There's a different thing also called "barrier", and a different different thing also called "fence", and there are many variants of "event" that are pretty different from Pythons (some of which are more like a condition, but aren't actually usable as such), and sometimes a "condition variable" is the actual shared state protected by the sync object rather than the sync object, and so on…
Post a Comment for "With-statement And Threading :making Function Execute Before Run"