mirror of
https://github.com/python/cpython.git
synced 2025-09-15 05:06:12 +00:00
bpo-1596321: Fix threading._shutdown() for the main thread (GH-28549)
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 95d3137082
)
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
c7fdd6879b
commit
38c67738c6
3 changed files with 53 additions and 8 deletions
|
@ -928,6 +928,39 @@ class ThreadTests(BaseTestCase):
|
||||||
b'is deprecated and will be removed in Python 3.12')
|
b'is deprecated and will be removed in Python 3.12')
|
||||||
self.assertIn(msg, err)
|
self.assertIn(msg, err)
|
||||||
|
|
||||||
|
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):
|
class ThreadJoinOnShutdown(BaseTestCase):
|
||||||
|
|
||||||
|
|
|
@ -1523,20 +1523,29 @@ def _shutdown():
|
||||||
|
|
||||||
global _SHUTTING_DOWN
|
global _SHUTTING_DOWN
|
||||||
_SHUTTING_DOWN = True
|
_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.
|
# Call registered threading atexit functions before threads are joined.
|
||||||
# Order is reversed, similar to atexit.
|
# Order is reversed, similar to atexit.
|
||||||
for atexit_call in reversed(_threading_atexits):
|
for atexit_call in reversed(_threading_atexits):
|
||||||
atexit_call()
|
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
|
# Join all non-deamon threads
|
||||||
while True:
|
while True:
|
||||||
with _shutdown_locks_lock:
|
with _shutdown_locks_lock:
|
||||||
|
|
|
@ -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.
|
Loading…
Add table
Add a link
Reference in a new issue