[3.12] gh-111644: Fix support threading_cleanup() (GH-111714) (#111716)

gh-111644: Fix support threading_cleanup() (GH-111714)

Copy the list of dangling threads to make sure that the list of
"Dangling thread" is complete. Previously, the list was incomplete if
threads completed just before the list was displayed.

Changes:

* Rewrite the warning to make it easier to understand.
* Use support.sleeping_retry().
* threading_cleanup() no longer copies threading._dangling,
  but only counts the number of dangling thread.
* Remove support.gc_support() call.
(cherry picked from commit f62c7ccf9a)

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Miss Islington (bot) 2023-11-04 01:56:34 +01:00 committed by GitHub
parent 1a95ad68b4
commit 02f8f781da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -22,34 +22,37 @@ from test import support
def threading_setup(): def threading_setup():
return _thread._count(), threading._dangling.copy() return _thread._count(), len(threading._dangling)
def threading_cleanup(*original_values): def threading_cleanup(*original_values):
_MAX_COUNT = 100 orig_count, orig_ndangling = original_values
for count in range(_MAX_COUNT): timeout = 1.0
values = _thread._count(), threading._dangling for _ in support.sleeping_retry(timeout, error=False):
if values == original_values: # Copy the thread list to get a consistent output. threading._dangling
break # is a WeakSet, its value changes when it's read.
dangling_threads = list(threading._dangling)
count = _thread._count()
if not count: if count <= orig_count:
# Display a warning at the first iteration return
support.environment_altered = True
dangling_threads = values[1]
support.print_warning(f"threading_cleanup() failed to cleanup "
f"{values[0] - original_values[0]} threads "
f"(count: {values[0]}, "
f"dangling: {len(dangling_threads)})")
for thread in dangling_threads:
support.print_warning(f"Dangling thread: {thread!r}")
# Don't hold references to threads # Timeout!
dangling_threads = None support.environment_altered = True
values = None support.print_warning(
f"threading_cleanup() failed to clean up threads "
f"in {timeout:.1f} seconds\n"
f" before: thread count={orig_count}, dangling={orig_ndangling}\n"
f" after: thread count={count}, dangling={len(dangling_threads)}")
for thread in dangling_threads:
support.print_warning(f"Dangling thread: {thread!r}")
time.sleep(0.01) # The warning happens when a test spawns threads and some of these threads
support.gc_collect() # are still running after the test completes. To fix this warning, join
# threads explicitly to wait until they complete.
#
# To make the warning more likely, reduce the timeout.
def reap_threads(func): def reap_threads(func):