|
22 | 22 |
|
23 | 23 |
|
24 | 24 | def threading_setup():
|
25 |
| - return _thread._count(), threading._dangling.copy() |
| 25 | + return _thread._count(), len(threading._dangling) |
26 | 26 |
|
27 | 27 |
|
28 | 28 | def threading_cleanup(*original_values):
|
29 |
| - _MAX_COUNT = 100 |
30 |
| - |
31 |
| - for count in range(_MAX_COUNT): |
32 |
| - values = _thread._count(), threading._dangling |
33 |
| - if values == original_values: |
34 |
| - break |
35 |
| - |
36 |
| - if not count: |
37 |
| - # Display a warning at the first iteration |
38 |
| - support.environment_altered = True |
39 |
| - dangling_threads = values[1] |
40 |
| - support.print_warning(f"threading_cleanup() failed to cleanup " |
41 |
| - f"{values[0] - original_values[0]} threads " |
42 |
| - f"(count: {values[0]}, " |
43 |
| - f"dangling: {len(dangling_threads)})") |
44 |
| - for thread in dangling_threads: |
45 |
| - support.print_warning(f"Dangling thread: {thread!r}") |
46 |
| - |
47 |
| - # Don't hold references to threads |
48 |
| - dangling_threads = None |
49 |
| - values = None |
50 |
| - |
51 |
| - time.sleep(0.01) |
52 |
| - support.gc_collect() |
| 29 | + orig_count, orig_ndangling = original_values |
| 30 | + |
| 31 | + timeout = 1.0 |
| 32 | + for _ in support.sleeping_retry(timeout, error=False): |
| 33 | + # Copy the thread list to get a consistent output. threading._dangling |
| 34 | + # is a WeakSet, its value changes when it's read. |
| 35 | + dangling_threads = list(threading._dangling) |
| 36 | + count = _thread._count() |
| 37 | + |
| 38 | + if count == orig_count: |
| 39 | + return |
| 40 | + |
| 41 | + # Timeout! |
| 42 | + support.environment_altered = True |
| 43 | + support.print_warning( |
| 44 | + f"threading_cleanup() failed to clean up threads " |
| 45 | + f"in {timeout:.1f} seconds\n" |
| 46 | + f" before: thread count={orig_count}, dangling={orig_ndangling}\n" |
| 47 | + f" after: thread count={count}, dangling={len(dangling_threads)}") |
| 48 | + for thread in dangling_threads: |
| 49 | + support.print_warning(f"Dangling thread: {thread!r}") |
| 50 | + |
| 51 | + # The warning happens when a test spawns threads and some of these threads |
| 52 | + # are still running after the test completes. To fix this warning, join |
| 53 | + # threads explicitly to wait until they complete. |
| 54 | + # |
| 55 | + # To make the warning more likely, reduce the timeout. |
53 | 56 |
|
54 | 57 |
|
55 | 58 | def reap_threads(func):
|
|
0 commit comments