summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/multiprocessing.rst2
-rw-r--r--Doc/library/threading.rst313
-rw-r--r--Doc/whatsnew/3.3.rst10
-rw-r--r--Misc/NEWS8
4 files changed, 162 insertions, 171 deletions
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
index 616b7cd..6c29e3f 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -916,7 +916,7 @@ object -- see :ref:`multiprocessing-managers`.
.. class:: Condition([lock])
- A condition variable: a clone of :class:`threading.Condition`.
+ A condition variable: an alias for :class:`threading.Condition`.
If *lock* is specified then it should be a :class:`Lock` or :class:`RLock`
object from :mod:`multiprocessing`.
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index 7ab739b..05863a0 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -21,7 +21,7 @@ The :mod:`dummy_threading` module is provided for situations where
supported by this module.
-This module defines the following functions and objects:
+This module defines the following functions:
.. function:: active_count()
@@ -30,16 +30,6 @@ This module defines the following functions and objects:
count is equal to the length of the list returned by :func:`.enumerate`.
-.. function:: Condition()
- :noindex:
-
- A factory function that returns a new condition variable object. A condition
- variable allows one or more threads to wait until they are notified by another
- thread.
-
- See :ref:`condition-objects`.
-
-
.. function:: current_thread()
Return the current :class:`Thread` object, corresponding to the caller's thread
@@ -67,88 +57,6 @@ This module defines the following functions and objects:
and threads that have not yet been started.
-.. function:: Event()
- :noindex:
-
- A factory function that returns a new event object. An event manages a flag
- that can be set to true with the :meth:`~Event.set` method and reset to false
- with the :meth:`clear` method. The :meth:`wait` method blocks until the flag
- is true.
-
- See :ref:`event-objects`.
-
-
-.. class:: local
-
- A class that represents thread-local data. Thread-local data are data whose
- values are thread specific. To manage thread-local data, just create an
- instance of :class:`local` (or a subclass) and store attributes on it::
-
- mydata = threading.local()
- mydata.x = 1
-
- The instance's values will be different for separate threads.
-
- For more details and extensive examples, see the documentation string of the
- :mod:`_threading_local` module.
-
-
-.. function:: Lock()
-
- A factory function that returns a new primitive lock object. Once a thread has
- acquired it, subsequent attempts to acquire it block, until it is released; any
- thread may release it.
-
- See :ref:`lock-objects`.
-
-
-.. function:: RLock()
-
- A factory function that returns a new reentrant lock object. A reentrant lock
- must be released by the thread that acquired it. Once a thread has acquired a
- reentrant lock, the same thread may acquire it again without blocking; the
- thread must release it once for each time it has acquired it.
-
- See :ref:`rlock-objects`.
-
-
-.. function:: Semaphore(value=1)
- :noindex:
-
- A factory function that returns a new semaphore object. A semaphore manages a
- counter representing the number of :meth:`release` calls minus the number of
- :meth:`acquire` calls, plus an initial value. The :meth:`acquire` method blocks
- if necessary until it can return without making the counter negative. If not
- given, *value* defaults to 1.
-
- See :ref:`semaphore-objects`.
-
-
-.. function:: BoundedSemaphore(value=1)
-
- A factory function that returns a new bounded semaphore object. A bounded
- semaphore checks to make sure its current value doesn't exceed its initial
- value. If it does, :exc:`ValueError` is raised. In most situations semaphores
- are used to guard resources with limited capacity. If the semaphore is released
- too many times it's a sign of a bug. If not given, *value* defaults to 1.
-
-
-.. class:: Thread
-
- A class that represents a thread of control. This class can be safely
- subclassed in a limited fashion.
-
- See :ref:`thread-objects`.
-
-
-.. class:: Timer
- :noindex:
-
- A thread that executes a function after a specified interval has passed.
-
- See :ref:`timer-objects`.
-
-
.. function:: settrace(func)
.. index:: single: trace function
@@ -197,7 +105,8 @@ This module also defines the following constant:
.. versionadded:: 3.2
-Detailed interfaces for the objects are documented below.
+This module defines a number of classes, which are detailed in the sections
+below.
The design of this module is loosely based on Java's threading model. However,
where Java makes locks and condition variables basic behavior of every object,
@@ -210,17 +119,38 @@ when implemented, are mapped to module-level functions.
All of the methods described below are executed atomically.
+Thread-Local Data
+-----------------
+
+Thread-local data is data whose values are thread specific. To manage
+thread-local data, just create an instance of :class:`local` (or a
+subclass) and store attributes on it::
+
+ mydata = threading.local()
+ mydata.x = 1
+
+The instance's values will be different for separate threads.
+
+
+.. class:: local()
+
+ A class that represents thread-local data.
+
+ For more details and extensive examples, see the documentation string of the
+ :mod:`_threading_local` module.
+
+
.. _thread-objects:
Thread Objects
--------------
-This class represents an activity that is run in a separate thread of control.
-There are two ways to specify the activity: by passing a callable object to the
-constructor, or by overriding the :meth:`~Thread.run` method in a subclass.
-No other methods (except for the constructor) should be overridden in a
-subclass. In other words, *only* override the :meth:`~Thread.__init__`
-and :meth:`~Thread.run` methods of this class.
+The :class:`Thread` class represents an activity that is run in a separate
+thread of control. There are two ways to specify the activity: by passing a
+callable object to the constructor, or by overriding the :meth:`~Thread.run`
+method in a subclass. No other methods (except for the constructor) should be
+overridden in a subclass. In other words, *only* override the
+:meth:`~Thread.__init__` and :meth:`~Thread.run` methods of this class.
Once a thread object is created, its activity must be started by calling the
thread's :meth:`~Thread.start` method. This invokes the :meth:`~Thread.run`
@@ -419,45 +349,55 @@ is not defined, and may vary across implementations.
All methods are executed atomically.
-.. method:: Lock.acquire(blocking=True, timeout=-1)
+.. class:: Lock()
- Acquire a lock, blocking or non-blocking.
+ The class implementing primitive lock objects. Once a thread has acquired a
+ lock, subsequent attempts to acquire it block, until it is released; any
+ thread may release it.
- When invoked with the *blocking* argument set to ``True`` (the default),
- block until the lock is unlocked, then set it to locked and return ``True``.
+ .. versionchanged:: 3.3
+ Changed from a factory function to a class.
- When invoked with the *blocking* argument set to ``False``, do not block.
- If a call with *blocking* set to ``True`` would block, return ``False``
- immediately; otherwise, set the lock to locked and return ``True``.
- When invoked with the floating-point *timeout* argument set to a positive
- value, block for at most the number of seconds specified by *timeout*
- and as long as the lock cannot be acquired. A negative *timeout* argument
- specifies an unbounded wait. It is forbidden to specify a *timeout*
- when *blocking* is false.
+ .. method:: acquire(blocking=True, timeout=-1)
- The return value is ``True`` if the lock is acquired successfully,
- ``False`` if not (for example if the *timeout* expired).
+ Acquire a lock, blocking or non-blocking.
- .. versionchanged:: 3.2
- The *timeout* parameter is new.
+ When invoked with the *blocking* argument set to ``True`` (the default),
+ block until the lock is unlocked, then set it to locked and return ``True``.
- .. versionchanged:: 3.2
- Lock acquires can now be interrupted by signals on POSIX.
+ When invoked with the *blocking* argument set to ``False``, do not block.
+ If a call with *blocking* set to ``True`` would block, return ``False``
+ immediately; otherwise, set the lock to locked and return ``True``.
+ When invoked with the floating-point *timeout* argument set to a positive
+ value, block for at most the number of seconds specified by *timeout*
+ and as long as the lock cannot be acquired. A negative *timeout* argument
+ specifies an unbounded wait. It is forbidden to specify a *timeout*
+ when *blocking* is false.
-.. method:: Lock.release()
+ The return value is ``True`` if the lock is acquired successfully,
+ ``False`` if not (for example if the *timeout* expired).
- Release a lock. This can be called from any thread, not only the thread
- which has acquired the lock.
+ .. versionchanged:: 3.2
+ The *timeout* parameter is new.
- When the lock is locked, reset it to unlocked, and return. If any other threads
- are blocked waiting for the lock to become unlocked, allow exactly one of them
- to proceed.
+ .. versionchanged:: 3.2
+ Lock acquires can now be interrupted by signals on POSIX.
+
+
+ .. method:: release()
+
+ Release a lock. This can be called from any thread, not only the thread
+ which has acquired the lock.
+
+ When the lock is locked, reset it to unlocked, and return. If any other threads
+ are blocked waiting for the lock to become unlocked, allow exactly one of them
+ to proceed.
- When invoked on an unlocked lock, a :exc:`RuntimeError` is raised.
+ When invoked on an unlocked lock, a :exc:`RuntimeError` is raised.
- There is no return value.
+ There is no return value.
.. _rlock-objects:
@@ -481,47 +421,59 @@ allows another thread blocked in :meth:`~Lock.acquire` to proceed.
Reentrant locks also support the :ref:`context manager protocol <with-locks>`.
-.. method:: RLock.acquire(blocking=True, timeout=-1)
+.. class:: RLock()
- Acquire a lock, blocking or non-blocking.
+ This class implements reentrant lock objects. A reentrant lock must be
+ released by the thread that acquired it. Once a thread has acquired a
+ reentrant lock, the same thread may acquire it again without blocking; the
+ thread must release it once for each time it has acquired it.
- When invoked without arguments: if this thread already owns the lock, increment
- the recursion level by one, and return immediately. Otherwise, if another
- thread owns the lock, block until the lock is unlocked. Once the lock is
- unlocked (not owned by any thread), then grab ownership, set the recursion level
- to one, and return. If more than one thread is blocked waiting until the lock
- is unlocked, only one at a time will be able to grab ownership of the lock.
- There is no return value in this case.
+ Note that ``RLock`` is actually a factory function which returns an instance
+ of the most efficient version of the concrete RLock class that is supported
+ by the platform.
- When invoked with the *blocking* argument set to true, do the same thing as when
- called without arguments, and return true.
- When invoked with the *blocking* argument set to false, do not block. If a call
- without an argument would block, return false immediately; otherwise, do the
- same thing as when called without arguments, and return true.
+ .. method:: acquire(blocking=True, timeout=-1)
- When invoked with the floating-point *timeout* argument set to a positive
- value, block for at most the number of seconds specified by *timeout*
- and as long as the lock cannot be acquired. Return true if the lock has
- been acquired, false if the timeout has elapsed.
+ Acquire a lock, blocking or non-blocking.
- .. versionchanged:: 3.2
- The *timeout* parameter is new.
+ When invoked without arguments: if this thread already owns the lock, increment
+ the recursion level by one, and return immediately. Otherwise, if another
+ thread owns the lock, block until the lock is unlocked. Once the lock is
+ unlocked (not owned by any thread), then grab ownership, set the recursion level
+ to one, and return. If more than one thread is blocked waiting until the lock
+ is unlocked, only one at a time will be able to grab ownership of the lock.
+ There is no return value in this case.
+ When invoked with the *blocking* argument set to true, do the same thing as when
+ called without arguments, and return true.
-.. method:: RLock.release()
+ When invoked with the *blocking* argument set to false, do not block. If a call
+ without an argument would block, return false immediately; otherwise, do the
+ same thing as when called without arguments, and return true.
- Release a lock, decrementing the recursion level. If after the decrement it is
- zero, reset the lock to unlocked (not owned by any thread), and if any other
- threads are blocked waiting for the lock to become unlocked, allow exactly one
- of them to proceed. If after the decrement the recursion level is still
- nonzero, the lock remains locked and owned by the calling thread.
+ When invoked with the floating-point *timeout* argument set to a positive
+ value, block for at most the number of seconds specified by *timeout*
+ and as long as the lock cannot be acquired. Return true if the lock has
+ been acquired, false if the timeout has elapsed.
- Only call this method when the calling thread owns the lock. A
- :exc:`RuntimeError` is raised if this method is called when the lock is
- unlocked.
+ .. versionchanged:: 3.2
+ The *timeout* parameter is new.
- There is no return value.
+
+ .. method:: release()
+
+ Release a lock, decrementing the recursion level. If after the decrement it is
+ zero, reset the lock to unlocked (not owned by any thread), and if any other
+ threads are blocked waiting for the lock to become unlocked, allow exactly one
+ of them to proceed. If after the decrement the recursion level is still
+ nonzero, the lock remains locked and owned by the calling thread.
+
+ Only call this method when the calling thread owns the lock. A
+ :exc:`RuntimeError` is raised if this method is called when the lock is
+ unlocked.
+
+ There is no return value.
.. _condition-objects:
@@ -556,10 +508,6 @@ not return from their :meth:`~Condition.wait` call immediately, but only when
the thread that called :meth:`~Condition.notify` or :meth:`~Condition.notify_all`
finally relinquishes ownership of the lock.
-
-Usage
-^^^^^
-
The typical programming style using condition variables uses the lock to
synchronize access to some shared state; threads that are interested in a
particular change of state call :meth:`~Condition.wait` repeatedly until they
@@ -598,15 +546,18 @@ waiting threads. E.g. in a typical producer-consumer situation, adding one
item to the buffer only needs to wake up one consumer thread.
-Interface
-^^^^^^^^^
-
.. class:: Condition(lock=None)
+ This class implements condition variable objects. A condition variable
+ allows one or more threads to wait until they are notified by another thread.
+
If the *lock* argument is given and not ``None``, it must be a :class:`Lock`
or :class:`RLock` object, and it is used as the underlying lock. Otherwise,
a new :class:`RLock` object is created and used as the underlying lock.
+ .. versionchanged:: 3.3
+ changed from a factory function to a class.
+
.. method:: acquire(*args)
Acquire the underlying lock. This method calls the corresponding method on
@@ -716,10 +667,19 @@ Semaphores also support the :ref:`context manager protocol <with-locks>`.
.. class:: Semaphore(value=1)
+ This class implements semaphore objects. A semaphore manages a counter
+ representing the number of :meth:`release` calls minus the number of
+ :meth:`acquire` calls, plus an initial value. The :meth:`acquire` method
+ blocks if necessary until it can return without making the counter negative.
+ If not given, *value* defaults to 1.
+
The optional argument gives the initial *value* for the internal counter; it
defaults to ``1``. If the *value* given is less than 0, :exc:`ValueError` is
raised.
+ .. versionchanged:: 3.3
+ changed from a factory function to a class.
+
.. method:: acquire(blocking=True, timeout=None)
Acquire a semaphore.
@@ -752,6 +712,18 @@ Semaphores also support the :ref:`context manager protocol <with-locks>`.
than zero again, wake up that thread.
+.. class:: BoundedSemaphore(value=1)
+
+ Class implementing bounded semaphore objects. A bounded semaphore checks to
+ make sure its current value doesn't exceed its initial value. If it does,
+ :exc:`ValueError` is raised. In most situations semaphores are used to guard
+ resources with limited capacity. If the semaphore is released too many times
+ it's a sign of a bug. If not given, *value* defaults to 1.
+
+ .. versionchanged:: 3.3
+ changed from a factory function to a class.
+
+
.. _semaphore-examples:
:class:`Semaphore` Example
@@ -763,7 +735,7 @@ you should use a bounded semaphore. Before spawning any worker threads, your
main thread would initialize the semaphore::
maxconnections = 5
- ...
+ # ...
pool_sema = BoundedSemaphore(value=maxconnections)
Once spawned, worker threads call the semaphore's acquire and release methods
@@ -772,7 +744,7 @@ when they need to connect to the server::
with pool_sema:
conn = connectdb()
try:
- ... use connection ...
+ # ... use connection ...
finally:
conn.close()
@@ -795,7 +767,13 @@ method. The :meth:`~Event.wait` method blocks until the flag is true.
.. class:: Event()
- The internal flag is initially false.
+ Class implementing event objects. An event manages a flag that can be set to
+ true with the :meth:`~Event.set` method and reset to false with the
+ :meth:`clear` method. The :meth:`wait` method blocks until the flag is true.
+ The flag is initially false.
+
+ .. versionchanged:: 3.3
+ changed from a factory function to a class.
.. method:: is_set()
@@ -860,6 +838,9 @@ For example::
Create a timer that will run *function* with arguments *args* and keyword
arguments *kwargs*, after *interval* seconds have passed.
+ .. versionchanged:: 3.3
+ changed from a factory function to a class.
+
.. method:: cancel()
Stop the timer, and cancel the execution of the timer's action. This will
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index 088ea4a..1fef8d3 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -1945,6 +1945,12 @@ of text (:issue:`13857`).
threading
---------
+:class:`threading.Condition`, :class:`threading.Semaphore`,
+:class:`threading.BoundedSempaphore`, :class:`threading.Event`, and
+:class:`threading.Timer`, all of which used to be factory functions returning a
+class instance, are now classes and may be subclassed. (Contributed by Éric
+Araujo in :issue:`109681`).
+
The :class:`threading.Thread` constructor now accepts a ``daemon`` keyword
argument to override the default behavior of inheriting the ``deamon`` flag
value from the parent thread (:issue:`6064`).
@@ -2331,6 +2337,10 @@ Porting Python code
make decisions affected by the AST version, use :attr:`sys.version_info`
to make the decision.
+* Code that used to work around the fact that the :mod:`threading` module used
+ factory functions by subclassing the private classes will need to change to
+ subclass the now-public classes.
+
Porting C code
--------------
diff --git a/Misc/NEWS b/Misc/NEWS
index 74c2004..be761e6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -3031,11 +3031,11 @@ Library
- Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod')
in Python code) now finds the doc of the method.
-- Issue #10968: Remove indirection in threading. The public names (Thread,
+- Issue #10968: Remove indirection in threading. The public names (Event,
Condition, etc.) used to be factory functions returning instances of hidden
- classes (_Thread, _Condition, etc.), because (if Guido recalls correctly) this
- code pre-dates the ability to subclass extension types. It is now possible to
- inherit from Thread and other classes, without having to import the private
+ classes (_Event, _Condition, etc.), because (if Guido recalls correctly) this
+ code pre-dates the ability to subclass extension types. It is now possible
+ to inherit from these classes, without having to import the private
underscored names like multiprocessing did.
- Issue #9723: Add shlex.quote functions, to escape filenames and command