diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-09-14 20:07:24 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-14 20:07:24 (GMT) |
commit | ff40ecda73178dfcad24e26240d684356ef20793 (patch) | |
tree | 0533f9354f838a97a67fc22749b1b1b7374691fb /Lib/test/support/__init__.py | |
parent | b8c7be2c523b012e57915182543d06657161057f (diff) | |
download | cpython-ff40ecda73178dfcad24e26240d684356ef20793.zip cpython-ff40ecda73178dfcad24e26240d684356ef20793.tar.gz cpython-ff40ecda73178dfcad24e26240d684356ef20793.tar.bz2 |
bpo-31234: Add test.support.wait_threads_exit() (#3578)
Use _thread.count() to wait until threads exit. The new context
manager prevents the "dangling thread" warning.
Diffstat (limited to 'Lib/test/support/__init__.py')
-rw-r--r-- | Lib/test/support/__init__.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index df23505..63f7a91 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2072,6 +2072,41 @@ def reap_threads(func): return decorator +@contextlib.contextmanager +def wait_threads_exit(timeout=60.0): + """ + 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() are designed to emit a warning + if a test leaves running threads in the background. This context manager + is designed to cleanup threads started by the _thread.start_new_thread() + which doesn't allow to wait for thread exit, whereas thread.Thread has a + join() method. + """ + old_count = _thread._count() + try: + yield + finally: + start_time = time.monotonic() + deadline = start_time + timeout + while True: + count = _thread._count() + if count <= old_count: + break + if time.monotonic() > deadline: + dt = time.monotonic() - start_time + msg = (f"wait_threads() failed to cleanup {count - old_count} " + f"threads after {dt:.1f} seconds " + f"(count: {count}, old count: {old_count})") + raise AssertionError(msg) + time.sleep(0.010) + gc_collect() + + def reap_children(): """Use this function at the end of test_main() whenever sub-processes are started. This will help ensure that no extra children (zombies) |