I have seen many questions similar to this one on this platform, but none of the answers quite resolve my current issue.
I have a program which sends/receives messages over a serial connection. Messages can be received at any time, so once the connection is established, I spawn two threads: one to read messages off the port and queue them, and one to handle the messages received. These threads must run indefinitely until the connection is closed. By default, python's behavior for dealing with exceptions in threads is to just print the exception to terminal and kill the thread. Obviously this is not going to work for me, and it seems the best solution so far is to somehow raise the exception in the main thread to show that the listener or processor thread had an exception and died.
How should I properly catch exceptions that occur within indefinitely-running IO threads in my program?
I have tried overriding threading.excepthook with a custom function to re-raise the exception, but this does not work for me, since that function still gets called from within the thread raising the exception, not the main thread.
I have attached a super simple code snippet to represent very generally what the code is currently doing.
import threading
from time import sleep
import random
keep_thread_going = True
def thread_func(delay):
while keep_thread_going:
sleep(delay)
# Simulate an exeption randomly occuring
if random.randint(0, 5) == 0:
raise Exception("The thread happened to throw an exception")
def except_hook_test(args):
print("Custom exception handing...")
raise args.exc_value # What do I do here to raise this exception in the main thread?
def main():
threading.excepthook = except_hook_test
thread_obj = threading.Thread(target=thread_func, args=[1], daemon=True)
thread_obj.start()
# Simulate doing other stuff while the thread is running
sleep(5)
# End the thread
global keep_thread_going
keep_thread_going = False
thread_obj.join()
print("Done")
main()
Exceptions can be sent back to the main thread via a queue. Capture the exception and send it back to the main thread to be re-raised. If you want to make it clear that the main thread is raising the exception, you can use
raise exception from original_exceptionsyntax:Output:
The exception can be serialized through a
multiprocessing.Queueas well, but needs a little more work to get the stack trace:Output: