Ending Non-daemon Threads When Shutting Down An Interactive Python Session
Solution 1:
Okay I found a way to do this myself.
Looking at the Python source-code, it turns out that at shutdown, Python attempts to join() all non-daemonic threads before completing the shutdown of the process. Which sort-of makes sense, except that this would be much more useful if there were a documented way to signal those threads. Which there isn't.
However, it is possible to re-implement the join() method of one's own class derived from Thread, which can that serve as a way to notify the subthread that it is supposed to shut itself down:
classMyThread(threading.Thread):
def__init__(self):
super().__init__()
self._quit_flag = Falsedef__del__(self):
print("Bye bye!")
defrun(self):
whilenot self._quit_flag:
print("Thread is alive!", threading.active_count(), threading.main_thread().is_alive())
for t in threading.enumerate():
print(t.is_alive())
time.sleep(0.500)
defrequest_quit(self):
self._quit_flag = Truedefjoin(self):
self.request_quit()
super().join()
However, this way of addressing the issue is a pretty much a hack, and it ignores the following passage from the 'threading' module docs (https://docs.python.org/3/library/threading.html):
The Thread class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, only override the __init__() and run() methods of this class.
It does, however, work beautifully.
Solution 2:
I am not sure if this would be acceptable, but the only way I can see around your problem is to start the interactive console from your script instead of with -i
flag. Then you would be able to carry on with your program to do the exit, after you terminate your interactive session:
import threading
import time
from code import InteractiveConsole
defexit_gracefully():
print("exiting gracefully now")
global mt
mt.request_quit()
mt.join()
classMyThread(threading.Thread):
def__init__(self):
super().__init__()
self._quit_flag = Falsedefrun(self):
whilenot self._quit_flag:
print("Thread is alive!")
time.sleep(0.500)
defrequest_quit(self):
self._quit_flag = True
mt = MyThread()
mt.start()
InteractiveConsole(locals=locals()).interact()
exit_gracefully()
This you would execute without -i
flag, only as
python3 test.py
It would still give you the interactive console as with python -i
, but now the script executes exit_gracefully()
after the interactive shell exits.
Solution 3:
I think the way you can do this is to register a cleanup function using atexit
and set your thread as a daemon, eg:
#! /usr/bin/env python3import threading
import time
import atexit
classMyThread(threading.Thread):
def__init__(self):
super().__init__()
# this ensures that atexit gets called.
self.daemon = True
self._quit_flag = Falsedefrun(self):
whilenot self._quit_flag:
print("Thread is alive!")
time.sleep(0.500)
print("cleanup can also go here")
defrequest_quit(self):
print("cleanup can go here")
self._quit_flag = True
mt = MyThread()
defcleanup():
mt.request_quit()
mt.join()
print("even more cleanup here, so many options!")
atexit.register(cleanup)
mt.start()
Post a Comment for "Ending Non-daemon Threads When Shutting Down An Interactive Python Session"