Cause python to exit if any thread has an exception Cause python to exit if any thread has an exception multithreading multithreading

Cause python to exit if any thread has an exception


Well, you could simply raise an error in your thread and have the main thread handle and report that error. From there you could even terminate the program.

For example on your worker thread:

try:    self.result = self.do_something_dangerous()except Exception as e:    import sys    self.exc_info = sys.exc_info()

and on main thread:

if self.exc_info:    raise self.exc_info[1].with_traceback(self.exc_info[2])return self.result

So to give you a more complete picture, your code might look like this:

import threadingclass ExcThread(threading.Thread):    def excRun(self):        pass        #Where your core program will run    def run(self):        self.exc = None        try:        # Possibly throws an exception            self.excRun()        except:            import sys            self.exc = sys.exc_info()            # Save details of the exception thrown             # DON'T rethrow,            # just complete the function such as storing            # variables or states as needed    def join(self):        threading.Thread.join(self)        if self.exc:            msg = "Thread '%s' threw an exception: %s" % (self.getName(), self.exc[1])            new_exc = Exception(msg)            raise new_exc.with_traceback(self.exc[2])

(I added an extra line to keep track of which thread is causing the error in case you have multiple threads, it's also good practice to name them)


My solution ended up being a happy marriage between the solution posted here and the SIGKILL solution piece from above. I added the following killall.py submodule to my package:

import threadingimport sysimport tracebackimport osimport signaldef sendKillSignal(etype, value, tb):    print('KILL ALL')    traceback.print_exception(etype, value, tb)    os.kill(os.getpid(), signal.SIGKILL)original_init = threading.Thread.__init__def patched_init(self, *args, **kwargs):    print("thread init'ed")    original_init(self, *args, **kwargs)    original_run = self.run    def patched_run(*args, **kw):        try:            original_run(*args, **kw)        except:            sys.excepthook(*sys.exc_info())    self.run = patched_rundef install():    sys.excepthook = sendKillSignal    threading.Thread.__init__ = patched_init

And then ran the install right away before any other threads are launched (of my own creation or from other imported libraries).