diff options
-rw-r--r-- | Doc/library/multiprocessing.rst | 2 | ||||
-rw-r--r-- | Doc/library/threading.rst | 313 | ||||
-rw-r--r-- | Doc/whatsnew/3.3.rst | 10 | ||||
-rw-r--r-- | Misc/NEWS | 8 |
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 -------------- @@ -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 |