[Python-checkins] r75959 - in python/branches/py3k: Doc/library/_thread.rst Lib/test/support.py Lib/test/test_thread.py Misc/NEWS Modules/_threadmodule.c

antoine.pitrou python-checkins at python.org
Fri Oct 30 18:25:12 CET 2009


Author: antoine.pitrou
Date: Fri Oct 30 18:25:12 2009
New Revision: 75959
Log:
Merged revisions 75958 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk
........
 r75958 | antoine.pitrou | 2009年10月30日 18:07:08 +0100 (ven., 30 oct. 2009) | 7 lines
 
 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().
........
Modified:
 python/branches/py3k/ (props changed)
 python/branches/py3k/Doc/library/_thread.rst
 python/branches/py3k/Lib/test/support.py
 python/branches/py3k/Lib/test/test_thread.py
 python/branches/py3k/Misc/NEWS
 python/branches/py3k/Modules/_threadmodule.c
Modified: python/branches/py3k/Doc/library/_thread.rst
==============================================================================
--- python/branches/py3k/Doc/library/_thread.rst	(original)
+++ python/branches/py3k/Doc/library/_thread.rst	Fri Oct 30 18:25:12 2009
@@ -103,6 +103,19 @@
 Availability: Windows, systems with POSIX threads.
 
 
+.. function:: _count()
+
+ Return the number of currently running Python threads, excluding the main
+ thread. The returned number comprises all threads created through
+ :func:`start_new_thread` as well as :class:`threading.Thread`, and not
+ yet finished.
+
+ This function is meant for internal and specialized purposes only. In
+ most applications :func:`threading.enumerate()` should be used instead.
+
+ .. versionadded:: 3.2
+
+
 Lock objects have the following methods:
 
 
Modified: python/branches/py3k/Lib/test/support.py
==============================================================================
--- python/branches/py3k/Lib/test/support.py	(original)
+++ python/branches/py3k/Lib/test/support.py	Fri Oct 30 18:25:12 2009
@@ -947,24 +947,29 @@
 #=======================================================================
 # 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)
Modified: python/branches/py3k/Lib/test/test_thread.py
==============================================================================
--- python/branches/py3k/Lib/test/test_thread.py	(original)
+++ python/branches/py3k/Lib/test/test_thread.py	Fri Oct 30 18:25:12 2009
@@ -4,6 +4,7 @@
 from test import support
 import _thread as thread
 import time
+import weakref
 
 
 NUMTASKS = 10
@@ -99,6 +100,32 @@
 
 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):
Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Fri Oct 30 18:25:12 2009
@@ -334,6 +334,12 @@
 Tests
 -----
 
+- 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:`_thread._count()`.
+
 - Issue #7151: fixed regrtest -j so that output to stderr from a test no
 longer runs the risk of causing the worker thread to fail.
 
Modified: python/branches/py3k/Modules/_threadmodule.c
==============================================================================
--- python/branches/py3k/Modules/_threadmodule.c	(original)
+++ python/branches/py3k/Modules/_threadmodule.c	Fri Oct 30 18:25:12 2009
@@ -14,7 +14,7 @@
 #include "pythread.h"
 
 static PyObject *ThreadError;
-
+static long nb_threads = 0;
 
 /* Lock objects */
 
@@ -439,6 +439,7 @@
 	tstate = PyThreadState_New(boot->interp);
 
 	PyEval_AcquireThread(tstate);
+	nb_threads++;
 	res = PyEval_CallObjectWithKeywords(
 		boot->func, boot->args, boot->keyw);
 	if (res == NULL) {
@@ -463,6 +464,7 @@
 	Py_DECREF(boot->args);
 	Py_XDECREF(boot->keyw);
 	PyMem_DEL(boot_raw);
+	nb_threads--;
 	PyThreadState_Clear(tstate);
 	PyThreadState_DeleteCurrent();
 	PyThread_exit_thread();
@@ -606,6 +608,18 @@
 A thread's identity may be reused for another thread after it exits.");
 
 static PyObject *
+thread__count(PyObject *self)
+{
+	return PyLong_FromLong(nb_threads);
+}
+
+PyDoc_STRVAR(_count_doc,
+"_count() -> integer\n\
+\n\
+Return the number of currently running (sub)threads.\n\
+This excludes the main thread.");
+
+static PyObject *
 thread_stack_size(PyObject *self, PyObject *args)
 {
 	size_t old_size;
@@ -678,6 +692,8 @@
 	 METH_NOARGS, interrupt_doc},
 	{"get_ident",		(PyCFunction)thread_get_ident, 
 	 METH_NOARGS, get_ident_doc},
+	{"_count",		(PyCFunction)thread__count, 
+	 METH_NOARGS, _count_doc},
 	{"stack_size",		(PyCFunction)thread_stack_size,
 				METH_VARARGS,
 				stack_size_doc},
@@ -748,6 +764,8 @@
 	if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
 		return NULL;
 
+	nb_threads = 0;
+
 	/* Initialize the C thread library */
 	PyThread_init_thread();
 	return m;


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /