-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
_thread.start_new_thread(): call sys.unraisablehook() to handle uncaught exceptions #81257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Python 3.8 now has 3 hooks for uncaught exceptions:
_thread.start_new_thread() calls none of these hooks, but directly logs the exception. I propose to modify it to reuse sys.unraisablehook(): see attached PR. -- Using threading.excepthook() would be another option, but _thread.start_new_thread() is usually wrapped in threading.Thread.run() which already uses threading.excepthook(). It might be surprising to see two bugs from the same thread using threading.excepthook(). Moreover, right now, _thread is the "low-level" API to access threads: it doesn't acces threading. I'm not comfortable by adding an inter-dependency between _thread (low-level) and threading (high-level). If threading.Thread.run() is correctly written, it should not raise an exception. In the worst case, threading.excepthook should handle the exception. _thread.start_new_thread() should never get an exception raised by threading if threading.excepthook does correctly its job. |
With PR 13617, the function which raised the exception can be retrieved using unraisable.object. If we used threading.excepthook, I don't see how we could pass this function into threading.ExceptHookArgs: ExceptHookArgs.thread is expected to be a threading.Thread object. |
This issue is a follow-up of:
Discussions around _thread.start_new_thead() exception: Antoine Pitrou: What if some C extension wants to report uncaught exceptions in C-created threads? Does it have to create a dummy Thread object? For example, how about threads created by _thread.start_new_thread? Serhiy Storchaka: |
It calls sys.excepthook() currently: import _thread
import threading
import sys
done = False
def hook(*args):
global done
print(threading.current_thread())
done = True
sys.excepthook = hook
def worker():
raise Exception
_thread.start_new_thread(worker, tuple())
while not done:
pass |
Output: Ah right, sys.excepthook is called! But "Unhandled exception in thread started by <function worker at 0x7fae27f212d0>" line is always written into stderr, it cannot be avoided :-( And sys.excepthook doesn't provide access to the thread function which caused the issue. |
I updated my PR description: _thread.start_new_thread() now logs uncaught exception raised by the |
Since the error handling for threading.Thread.run() is written on Python there are many opportunities to get an exception in error handling: KeyboardInterrupt, MemoryError and, at the shutdown stage, maybe NameError, AttributeError or TypeError. |
Sure, the risk is real, but I tried to minimize it. NameError and AttributeError "should" not happen: I wrote _make_invoke_excepthook() to prevent name errors. Functions used to invoke threading.excepthook are "cached" in a private namespace. Moreover, the default hook is implemented in C also to reduce the risk of raising a new exception. Anyway, if threading.excepthook() raises a second exception, sys.excepthook() is now called to handle it ;-) That's a Python 3.8 change. In Python 3.7 and older, new exception was handled by start_new_thread(). |
Thanks Serhiy for the review! |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: