bpo-31234: Context manager to wait until all threads created in the with statement exit. Use _thread.count() to check if threads exited. Indirectly, wait until threads exit the internal t_bootstrap() C function of the _thread module. threading_setup() and threading_cleanup() a
(timeout=None)
| 71 | |
| 72 | @contextlib.contextmanager |
| 73 | def wait_threads_exit(timeout=None): |
| 74 | """ |
| 75 | bpo-31234: Context manager to wait until all threads created in the with |
| 76 | statement exit. |
| 77 | |
| 78 | Use _thread.count() to check if threads exited. Indirectly, wait until |
| 79 | threads exit the internal t_bootstrap() C function of the _thread module. |
| 80 | |
| 81 | threading_setup() and threading_cleanup() are designed to emit a warning |
| 82 | if a test leaves running threads in the background. This context manager |
| 83 | is designed to cleanup threads started by the _thread.start_new_thread() |
| 84 | which doesn't allow to wait for thread exit, whereas thread.Thread has a |
| 85 | join() method. |
| 86 | """ |
| 87 | if timeout is None: |
| 88 | timeout = support.SHORT_TIMEOUT |
| 89 | old_count = _thread._count() |
| 90 | try: |
| 91 | yield |
| 92 | finally: |
| 93 | start_time = time.monotonic() |
| 94 | for _ in support.sleeping_retry(timeout, error=False): |
| 95 | support.gc_collect() |
| 96 | count = _thread._count() |
| 97 | if count <= old_count: |
| 98 | break |
| 99 | else: |
| 100 | dt = time.monotonic() - start_time |
| 101 | msg = (f"wait_threads() failed to cleanup {count - old_count} " |
| 102 | f"threads after {dt:.1f} seconds " |
| 103 | f"(count: {count}, old count: {old_count})") |
| 104 | raise AssertionError(msg) |
| 105 | |
| 106 | |
| 107 | def join_thread(thread, timeout=None): |
nothing calls this directly
no test coverage detected
searching dependent graphs…