Python threading: will Event.set() really notify every waiting thread Python threading: will Event.set() really notify every waiting thread python python

Python threading: will Event.set() really notify every waiting thread


In the internals of Python, an event is implemented with a Condition() object.

When calling the event.set() method, the notify_all() of the condition is called (after getting the lock to be sure to be not interrupted), then all the threads receive the notification (the lock is released only when all the threads are notified), so you can be sure that all the threads will effectively be notified.

Now, clearing the event just after the notification is not a problem.... until you do not want to check the event value in the waiting threads with an event.is_set(), but you only need this kind of check if you were waiting with a timeout.

Examples :

pseudocode that works :

#in main threadevent = Event()thread1(event)thread2(event)...event.set()event.clear()#in thread code...event.wait()#do the stuff

pseudocode that may not work :

#in main threadevent = Event()thread1(event)thread2(event)...event.set()event.clear()#in thread code...while not event.is_set():   event.wait(timeout_value)#do the stuff

Edited : in python >= 2.7 you can still wait for an event with a timeout and be sure of the state of the event :

event_state = event.wait(timeout)while not event_state:    event_state = event.wait(timeout)


It's easy enough to verify that things work as expected (Note: this is Python 2 code, which will need adapting for Python 3):

import threadinge = threading.Event()threads = []def runner():    tname = threading.current_thread().name    print 'Thread waiting for event: %s' % tname    e.wait()    print 'Thread got event: %s' % tnamefor t in range(100):    t = threading.Thread(target=runner)    threads.append(t)    t.start()raw_input('Press enter to set and clear the event:')e.set()e.clear()for t in threads:    t.join()print 'All done.'

If you run the above script and it terminates, all should be well :-) Notice that a hundred threads are waiting for the event to be set; it's set and cleared straight away; all threads should see this and should terminate (though not in any definite order, and the "All done" can be printed anywhere after the "Press enter" prompt, not just at the very end.


Python 3+

It's easier to check that it works

import threadingimport timelock = threading.Lock() # just to sync printinge = threading.Event()threads = []def runner():    tname = threading.current_thread().name    with lock:        print('Thread waiting for event ', tname)    e.wait()    with lock:        print('Thread got event: ', tname)for t in range(8): # Create 8 threads could be 100's    t = threading.Thread(target=runner)    threads.append(t)    t.start()time.sleep(1) # force wait until set/cleare.set()e.clear()for t in threads:    t.join()        print('Done')