[Python-checkins] bpo-1596321: Fix threading._shutdown() for the main thread (GH-28549) (GH-28589)
vstinner
webhook-mailer at python.org
Mon Sep 27 17:40:27 EDT 2021
https://github.com/python/cpython/commit/94d19f606fa18a1c4d2faca1caf2f470a8ce6d46
commit: 94d19f606fa18a1c4d2faca1caf2f470a8ce6d46
branch: 3.9
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2021-09-27T23:40:22+02:00
summary:
bpo-1596321: Fix threading._shutdown() for the main thread (GH-28549) (GH-28589)
Fix the threading._shutdown() function when the threading module was
imported first from a thread different than the main thread: no
longer log an error at Python exit.
(cherry picked from commit 95d31370829b7d729667588e0a9943217401ea5b)
files:
A Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst
M Lib/test/test_threading.py
M Lib/threading.py
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index a57085b75d58a..af480b9014ed9 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -814,6 +814,39 @@ def noop(): pass
threading.Thread(target=noop).start()
# Thread.join() is not called
+ def test_import_from_another_thread(self):
+ # bpo-1596321: If the threading module is first import from a thread
+ # different than the main thread, threading._shutdown() must handle
+ # this case without logging an error at Python exit.
+ code = textwrap.dedent('''
+ import _thread
+ import sys
+
+ event = _thread.allocate_lock()
+ event.acquire()
+
+ def import_threading():
+ import threading
+ event.release()
+
+ if 'threading' in sys.modules:
+ raise Exception('threading is already imported')
+
+ _thread.start_new_thread(import_threading, ())
+
+ # wait until the threading module is imported
+ event.acquire()
+ event.release()
+
+ if 'threading' not in sys.modules:
+ raise Exception('threading is not imported')
+
+ # don't wait until the thread completes
+ ''')
+ rc, out, err = assert_python_ok("-c", code)
+ self.assertEqual(out, b'')
+ self.assertEqual(err, b'')
+
class ThreadJoinOnShutdown(BaseTestCase):
diff --git a/Lib/threading.py b/Lib/threading.py
index 1c98b3b2cdf46..448f152600c53 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -1433,20 +1433,29 @@ def _shutdown():
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
- # been released.
- assert tlock is not None
- assert tlock.locked()
- 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()
+ # Main thread
+ if _main_thread.ident == get_ident():
+ tlock = _main_thread._tstate_lock
+ # The main thread isn't finished yet, so its thread state lock can't
+ # have been released.
+ assert tlock is not None
+ assert tlock.locked()
+ tlock.release()
+ _main_thread._stop()
+ else:
+ # bpo-1596321: _shutdown() must be called in the main thread.
+ # If the threading module was not imported by the main thread,
+ # _main_thread is the thread which imported the threading module.
+ # In this case, ignore _main_thread, similar behavior than for threads
+ # spawned by C libraries or using _thread.start_new_thread().
+ pass
+
# Join all non-deamon threads
while True:
with _shutdown_locks_lock:
diff --git a/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst b/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst
new file mode 100644
index 0000000000000..61a3e5abf395e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst
@@ -0,0 +1,3 @@
+Fix the :func:`threading._shutdown` function when the :mod:`threading` module
+was imported first from a thread different than the main thread: no longer log
+an error at Python exit.
More information about the Python-checkins
mailing list