|
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