In a Python code I have a function that is running in a separate thread and looks something like this:
import threading
import sleep
class Foo:
def __init__(self):
self._thread = None
self._event = threading.Event()
def start():
if not self._event.is_set():
self._event.set()
self._thread = threading.Thread(target=self._some_function)
self._thread.start()
def stop():
if self._event.is_set():
self._event.clear()
self._thread.join()
self._thread = None
def _some_function():
while self._event.is_set():
do_something()
time.sleep(2)
if __name__ == "__main__":
foo = Foo()
foo.start()
foo.stop()
In the worst case it takes Foo.stop()
full 2 seconds to stop the code, which is a bit problematic. I'm trying to find a way in Python to solve this, i.e. abort the sleep if self._event.is_set()
does not return True
anymore.
I found some threads that relate to this question, i.e. this and this, but I don't think they can be really applied to this situation...
Any advice on this?
CodePudding user response:
As I know, you can't awake a sleeping subthread when you use time.sleep()
, but you can awake a sleeping mainthread
, using signal mechanism.
If you want to awake a thread before the timeout expire, you can use wait()
method from threading.Event()
class. This method gives you control to awake a subthread/mainthread
before the timeout expire. Below changes will solve your problem ;
import threading
import time
class Foo:
def __init__(self):
self._thread = None
self._event = threading.Event()
self._event2 = threading.Event()
def start(self):
if not self._event.is_set():
self._event.set()
self._thread = threading.Thread(target=self._some_function)
self._thread.start()
def stop(self):
if self._event.is_set():
self._event2.set()
self._event.clear()
self._thread.join()
self._thread = None
def _some_function(self):
while self._event.is_set():
self._event2.wait(2)
self._event2.clear()
do_something()
if __name__ == "__main__":
foo = Foo()
foo.start()
foo.stop()
CodePudding user response:
I think the following should do it, even if the logic is a bit backwards (at least to what I would intuitively do):
import threading
import sleep
class Foo:
def __init__(self):
self._thread = None
self._stop_thread = threading.Event()
self._stop_thread.set()
def start():
if self._stop_thread.is_set():
self._stop_thread.clear()
self._thread = threading.Thread(target=self._some_function)
self._thread.start()
def stop():
if not self._stop_thread.is_set():
self._stop_thread.set()
self._thread.join()
self._thread = None
def _some_function():
while not self._stop_thread.is_set():
self._stop_thread.wait(amount_of_time)
do_something()
if __name__ == "__main__":
foo = Foo()
foo.start()
foo.stop()
This avoids the need for two conditional variables.