[Python-checkins] r75958 - in python/trunk: Doc/library/thread.rst Lib/test/test_support.py Lib/test/test_thread.py Misc/NEWS Modules/threadmodule.c
Brett Cannon
brett at python.org
Fri Oct 30 21:13:11 CET 2009
If the new function is private, why document it?
On Fri, Oct 30, 2009 at 10:27, antoine.pitrou
<python-checkins at python.org> wrote:
> Author: antoine.pitrou
> Date: Fri Oct 30 18:07:08 2009
> New Revision: 75958
>
> Log:
> 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/trunk/Doc/library/thread.rst
> python/trunk/Lib/test/test_support.py
> python/trunk/Lib/test/test_thread.py
> python/trunk/Misc/NEWS
> python/trunk/Modules/threadmodule.c
>
> Modified: python/trunk/Doc/library/thread.rst
> ==============================================================================
> --- python/trunk/Doc/library/thread.rst (original)
> +++ python/trunk/Doc/library/thread.rst Fri Oct 30 18:07:08 2009
> @@ -112,6 +112,20 @@
>
> .. versionadded:: 2.5
>
> +
> +.. 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:: 2.7
> +
> +
> Lock objects have the following methods:
>
>
>
> Modified: python/trunk/Lib/test/test_support.py
> ==============================================================================
> --- python/trunk/Lib/test/test_support.py (original)
> +++ python/trunk/Lib/test/test_support.py Fri Oct 30 18:07:08 2009
> @@ -952,24 +952,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/trunk/Lib/test/test_thread.py
> ==============================================================================
> --- python/trunk/Lib/test/test_thread.py (original)
> +++ python/trunk/Lib/test/test_thread.py Fri Oct 30 18:07:08 2009
> @@ -4,6 +4,7 @@
> from test import test_support
> import thread
> import time
> +import weakref
>
>
> NUMTASKS = 10
> @@ -101,6 +102,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/trunk/Misc/NEWS
> ==============================================================================
> --- python/trunk/Misc/NEWS (original)
> +++ python/trunk/Misc/NEWS Fri Oct 30 18:07:08 2009
> @@ -1525,6 +1525,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/trunk/Modules/threadmodule.c
> ==============================================================================
> --- python/trunk/Modules/threadmodule.c (original)
> +++ python/trunk/Modules/threadmodule.c Fri Oct 30 18:07:08 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 PyInt_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},
> @@ -735,6 +751,8 @@
> if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
> return;
>
> + nb_threads = 0;
> +
> /* Initialize the C thread library */
> PyThread_init_thread();
> }
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
More information about the Python-checkins
mailing list