diff options
author | Kyle Stanley <aeros167@gmail.com> | 2020-03-27 19:31:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-27 19:31:22 (GMT) |
commit | b61b818d916942aad1f8f3e33181801c4a1ed14b (patch) | |
tree | e755041eb620f5b2937639b32c0b98d1afa54c89 /Lib/threading.py | |
parent | 5f9c131c099d6675d1a9d0228497865488afd548 (diff) | |
download | cpython-b61b818d916942aad1f8f3e33181801c4a1ed14b.zip cpython-b61b818d916942aad1f8f3e33181801c4a1ed14b.tar.gz cpython-b61b818d916942aad1f8f3e33181801c4a1ed14b.tar.bz2 |
bpo-39812: Remove daemon threads in concurrent.futures (GH-19149)
Remove daemon threads from :mod:`concurrent.futures` by adding
an internal `threading._register_atexit()`, which calls registered functions
prior to joining all non-daemon threads. This allows for compatibility
with subinterpreters, which don't support daemon threads.
Diffstat (limited to 'Lib/threading.py')
-rw-r--r-- | Lib/threading.py | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/Lib/threading.py b/Lib/threading.py index 46eb1b9..6b25e7a 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -3,6 +3,7 @@ import os as _os import sys as _sys import _thread +import functools from time import monotonic as _time from _weakrefset import WeakSet @@ -1346,6 +1347,27 @@ def enumerate(): with _active_limbo_lock: return list(_active.values()) + list(_limbo.values()) + +_threading_atexits = [] +_SHUTTING_DOWN = False + +def _register_atexit(func, *arg, **kwargs): + """CPython internal: register *func* to be called before joining threads. + + The registered *func* is called with its arguments just before all + non-daemon threads are joined in `_shutdown()`. It provides a similar + purpose to `atexit.register()`, but its functions are called prior to + threading shutdown instead of interpreter shutdown. + + For similarity to atexit, the registered functions are called in reverse. + """ + if _SHUTTING_DOWN: + raise RuntimeError("can't register atexit after shutdown") + + call = functools.partial(func, *arg, **kwargs) + _threading_atexits.append(call) + + from _thread import stack_size # Create the main thread object, @@ -1367,6 +1389,8 @@ def _shutdown(): # _shutdown() was already called return + global _SHUTTING_DOWN + _SHUTTING_DOWN = True # Main thread tlock = _main_thread._tstate_lock # The main thread isn't finished yet, so its thread state lock can't have @@ -1376,6 +1400,11 @@ def _shutdown(): tlock.release() _main_thread._stop() + # Call registered threading atexit functions before threads are joined. + # Order is reversed, similar to atexit. + for atexit_call in reversed(_threading_atexits): + atexit_call() + # Join all non-deamon threads while True: with _shutdown_locks_lock: |