Skip to content

Commit

Permalink
pythongh-111644: Fix support threading_cleanup()
Browse files Browse the repository at this point in the history
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 is displayed.

Changes:

* Reformat the warning to make it easier to understand.
* Use support.sleeping_retry().
* threading_cleanup() no longer copies threading._dangling: it only
  counts the number of dangling thread.
* Remove support.gc_support() call.
  • Loading branch information
vstinner committed Nov 3, 2023
1 parent f21b230 commit b1001dd
Showing 1 changed file with 28 additions and 25 deletions.
53 changes: 28 additions & 25 deletions Lib/test/support/threading_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,37 @@


def threading_setup():
return _thread._count(), threading._dangling.copy()
return _thread._count(), len(threading._dangling)


def threading_cleanup(*original_values):
_MAX_COUNT = 100

for count in range(_MAX_COUNT):
values = _thread._count(), threading._dangling
if values == original_values:
break

if not count:
# Display a warning at the first iteration
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
dangling_threads = None
values = None

time.sleep(0.01)
support.gc_collect()
orig_count, orig_ndangling = original_values

timeout = 1.0
for _ in support.sleeping_retry(timeout, error=False):
# Copy the thread list to get a consistent output. threading._dangling
# is a WeakSet, its value changes when it's read.
dangling_threads = list(threading._dangling)
count = _thread._count()

if count == orig_count:
return

# Timeout!
support.environment_altered = True
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}")

# The warning happens when a test spawns threads and some of these threads
# 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):
Expand Down

0 comments on commit b1001dd

Please sign in to comment.