2

I modified the following code from first answer on this link.

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self, target, timeout):
        super(StoppableThread, self).__init__()
        self._target = target
        self._timeout = timeout
        self._stop = threading.Event()
        self.awake = threading.Event()

    def run(self):
        while(not self._stop.isSet()):
            self.awake.clear()
            time.sleep(self._timeout)
            self.awake.set()
            self._target()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

Once I create an instance of this class and set it to daemon process, I would like to terminate it at a later time, when the thread is sleeping, else wait for it to complete the _target() function and then terminate. I am able to handle the latter case by calling stop method. However, I have no idea of terminating it when the _awake event object is set to False. Can someone please help?

Community
  • 1
  • 1
zorro
  • 94
  • 2
  • 10

1 Answers1

2

Your thread doesn't have to explicitly sleep. It can simply wait for another thread to ask it to stop.

def run(self):
    while(not self._stop.isSet()):
        self.awake.clear()
        self._stop.wait(self._timeout)  # instead of sleeping
        if self._stop.isSet():
            continue
        self.awake.set()
        self._target()

For this purpose, you don't need the awake event at all. (You might still need it if another thread wants to check its "status". I don't know if that's a requirement you have).

Without awake, your code will be:

class StoppableThread(threading.Thread):

    def __init__(self, target, timeout):
        super(StoppableThread, self).__init__()
        self._target = target
        self._timeout = timeout
        self._stop = threading.Event()

    def run(self):
        while not self.stopped():
            self._stop.wait(self._timeout)  # instead of sleeping
            if self.stopped():
                continue
            self._target()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()
shx2
  • 61,779
  • 13
  • 130
  • 153
  • I got your point. Now say if the function `target` runs infinitely long, how do I terminate it gracefully? I need to terminate it gracefully because it contains MySQL DB transactions. I don't have any timeout conditions for that function like the above case, where I could run the function `target` periodically after every timeout seconds. Do I create a driver function for that function, run the driver function from a new thread, and pass the `_stop` event flag from the above thread to it? Or is there a better way? – zorro Mar 23 '16 at 09:57
  • @zorro, since this is a completely different question, you should post a new question (the rule is one question per post) – shx2 Mar 23 '16 at 10:08