[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