0

I want to make a thread and control it with an event object. Detailedly speaking, I want the thread to be executed whenever the event object is set and to wait itselt, repeatedly.

The below shows a sketchy logic I thought of.

import threading
import time

e = threading.Event()

def start_operation():
    e.wait()

    while e.is_set():
        print('STARTING TASK')

        e.clear()



t1 = threading.Thread(target=start_operation)
t1.start()

e.set()    # first set
e.set()    # second set

I expected t1 to run once the first set has been commanded and to stop itself(due to e.clear inside it), and then to run again after the second set has been commanded. So, accordign to what I expected, it should print out 'STARTING TASK' two times. But it shows it only once, which I don't understand why. How am I supposed to change the code to make it run the while loop again, whenever the event object is set?

1
  • Once you exit a while loop, you've exited it; changing the predicate back won't change anything. To make that work, you'd need another while loop, maybe a while True:, around the whole thing (including the e.wait()). Commented Jun 19, 2018 at 0:48

1 Answer 1

4

The first problem is that once you exit a while loop, you've exited it. Changing the predicate back won't change anything. Forget about events for a second and just look at this code:

i = 0
while i == 0:
    i = 1

It obviously doesn't matter if you set i = 0 again later, right? You've already left the while loop, and the whole function. And your code is doing exactly the same thing.

You can fix problem that by just adding another while loop around the whole thing:

def start_operation():
    while True:
        e.wait()

        while e.is_set():
            print('STARTING TASK')

            e.clear()

However, that still isn't going to work—except maybe occasionally, by accident.

Event.set doesn't block; it just sets the event immediately, even if it's already set. So, the most likely flow of control here is:

  • background thread hits e.wait() and blocks.
  • main thread hits e.set() and sets event.
  • main thread hits e.set() and sets event again, with no effect.
  • background thread wakes up, does the loop once, calls e.clear() at the end.
  • background thread waits forever on e.wait().

(The fact that there's no way to avoid missed signals with events is effectively the reason conditions were invented, and that anything newer than Win32 and Python doesn't bother with events… But a condition isn't sufficient here either.)


If you want the main thread to block until the event is clear, and only then set it again, you can't do that. You need something extra, like a second event, which the main thread can wait on and the background thread can set.


But if you want to keep track of multiple set calls, without missing any, you need to use a different sync mechanism. A queue.Queue may be overkill here, but it's dead simple to do in Python, so let's just use that. Of course you don't actually have any values to put on the queue, but that's OK; you can just stick a dummy value there:

import queue
import threading

q = queue.Queue()

def start_operation():
    while True:
        _ = q.get()
        print('STARTING TASK')

t1 = threading.Thread(target=start_operation)
t1.start()

q.put(None)
q.put(None)

And if you later want to add a way to shut down the background thread, just change it to stick values on:

import queue
import threading

q = queue.Queue()

def start_operation():
    while True:
        if q.get():
            return
        print('STARTING TASK')    

t1 = threading.Thread(target=start_operation)
t1.start()

q.put(False)
q.put(False)
q.put(True)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your detailed answer! I have learened a lot from you and I appreciate it!

Your Answer

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.