diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2009-10-30 17:07:08 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2009-10-30 17:07:08 (GMT) |
commit | 59c44f36e0a575671c0e8dab6a9de88666e481b0 (patch) | |
tree | d56d849af56fbc8af46e39c316cbfb1bb86cce36 /Lib/test | |
parent | 93c21714946d5fa287bb4aa1d9acb46d55f0b742 (diff) | |
download | cpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.zip cpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.tar.gz cpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.tar.bz2 |
Issue #7222: Make thread "reaping" more reliable so that reference
leak-chasing test runs give sensible results. The previous method of
reaping threads could return successfully while some Thread objects were
still referenced. This also introduces a new private function:
:func:hread._count().
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_support.py | 29 | ||||
-rw-r--r-- | Lib/test/test_thread.py | 27 |
2 files changed, 44 insertions, 12 deletions
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index bfa3c45..fa46be2 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -952,24 +952,29 @@ def run_doctest(module, verbosity=None): #======================================================================= # Threading support to prevent reporting refleaks when running regrtest.py -R +# NOTE: we use thread._count() rather than threading.enumerate() (or the +# moral equivalent thereof) because a threading.Thread object is still alive +# until its __bootstrap() method has returned, even after it has been +# unregistered from the threading module. +# thread._count(), on the other hand, only gets decremented *after* the +# __bootstrap() method has returned, which gives us reliable reference counts +# at the end of a test run. + def threading_setup(): - import threading - return len(threading._active), len(threading._limbo) + import thread + return thread._count(), -def threading_cleanup(num_active, num_limbo): - import threading +def threading_cleanup(nb_threads): + import thread import time _MAX_COUNT = 10 - count = 0 - while len(threading._active) != num_active and count < _MAX_COUNT: - count += 1 - time.sleep(0.1) - - count = 0 - while len(threading._limbo) != num_limbo and count < _MAX_COUNT: - count += 1 + for count in range(_MAX_COUNT): + n = thread._count() + if n == nb_threads: + break time.sleep(0.1) + # XXX print a warning in case of failure? def reap_threads(func): @functools.wraps(func) diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py index 66ad22f..4945047 100644 --- a/Lib/test/test_thread.py +++ b/Lib/test/test_thread.py @@ -4,6 +4,7 @@ import random from test import test_support import thread import time +import weakref NUMTASKS = 10 @@ -101,6 +102,32 @@ class ThreadRunningTests(BasicThreadTest): thread.stack_size(0) + def test__count(self): + # Test the _count() function. + orig = thread._count() + mut = thread.allocate_lock() + mut.acquire() + started = [] + def task(): + started.append(None) + mut.acquire() + mut.release() + thread.start_new_thread(task, ()) + while not started: + time.sleep(0.01) + self.assertEquals(thread._count(), orig + 1) + # Allow the task to finish. + mut.release() + # The only reliable way to be sure that the thread ended from the + # interpreter's point of view is to wait for the function object to be + # destroyed. + done = [] + wr = weakref.ref(task, lambda _: done.append(None)) + del task + while not done: + time.sleep(0.01) + self.assertEquals(thread._count(), orig) + class Barrier: def __init__(self, num_threads): |