mirror of
https://github.com/python/cpython.git
synced 2025-07-30 06:34:15 +00:00
Issue #8799: Fix and improve the threading.Condition documentation.
This commit is contained in:
parent
88b957a0ab
commit
126aef768d
2 changed files with 59 additions and 49 deletions
|
@ -503,62 +503,73 @@ Condition Objects
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A condition variable is always associated with some kind of lock; this can be
|
A condition variable is always associated with some kind of lock; this can be
|
||||||
passed in or one will be created by default. (Passing one in is useful when
|
passed in or one will be created by default. Passing one in is useful when
|
||||||
several condition variables must share the same lock.)
|
several condition variables must share the same lock. The lock is part of
|
||||||
|
the condition object: you don't have to track it separately.
|
||||||
|
|
||||||
A condition variable has :meth:`acquire` and :meth:`release` methods that call
|
A condition variable obeys the :term:`context manager` protocol: using the
|
||||||
the corresponding methods of the associated lock. It also has a :meth:`wait`
|
``with`` statement acquires the associated lock for the duration of the
|
||||||
method, and :meth:`notify` and :meth:`notify_all` methods. These three must only
|
enclosed block. The :meth:`~Condition.acquire` and :meth:`~Condition.release`
|
||||||
be called when the calling thread has acquired the lock, otherwise a
|
methods also call the corresponding methods of the associated lock.
|
||||||
:exc:`RuntimeError` is raised.
|
|
||||||
|
|
||||||
The :meth:`wait` method releases the lock, and then blocks until it is awakened
|
Other methods must be called with the associated lock held. The
|
||||||
by a :meth:`notify` or :meth:`notify_all` call for the same condition variable in
|
:meth:`~Condition.wait` method releases the lock, and then blocks until
|
||||||
another thread. Once awakened, it re-acquires the lock and returns. It is also
|
another thread awakens it by calling :meth:`~Condition.notify` or
|
||||||
possible to specify a timeout.
|
:meth:`~Condition.notify_all`. Once awakened, :meth:`~Condition.wait`
|
||||||
|
re-acquires the lock and returns. It is also possible to specify a timeout.
|
||||||
|
|
||||||
The :meth:`notify` method wakes up one of the threads waiting for the condition
|
The :meth:`~Condition.notify` method wakes up one of the threads waiting for
|
||||||
variable, if any are waiting. The :meth:`notify_all` method wakes up all threads
|
the condition variable, if any are waiting. The :meth:`~Condition.notify_all`
|
||||||
waiting for the condition variable.
|
method wakes up all threads waiting for the condition variable.
|
||||||
|
|
||||||
Note: the :meth:`notify` and :meth:`notify_all` methods don't release the lock;
|
Note: the :meth:`~Condition.notify` and :meth:`~Condition.notify_all` methods
|
||||||
this means that the thread or threads awakened will not return from their
|
don't release the lock; this means that the thread or threads awakened will
|
||||||
:meth:`wait` call immediately, but only when the thread that called
|
not return from their :meth:`~Condition.wait` call immediately, but only when
|
||||||
:meth:`notify` or :meth:`notify_all` finally relinquishes ownership of the lock.
|
the thread that called :meth:`~Condition.notify` or :meth:`~Condition.notify_all`
|
||||||
|
finally relinquishes ownership of the lock.
|
||||||
|
|
||||||
Tip: the typical programming style using condition variables uses the lock to
|
|
||||||
|
Usage
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
The typical programming style using condition variables uses the lock to
|
||||||
synchronize access to some shared state; threads that are interested in a
|
synchronize access to some shared state; threads that are interested in a
|
||||||
particular change of state call :meth:`wait` repeatedly until they see the
|
particular change of state call :meth:`~Condition.wait` repeatedly until they
|
||||||
desired state, while threads that modify the state call :meth:`notify` or
|
see the desired state, while threads that modify the state call
|
||||||
:meth:`notify_all` when they change the state in such a way that it could
|
:meth:`~Condition.notify` or :meth:`~Condition.notify_all` when they change
|
||||||
possibly be a desired state for one of the waiters. For example, the following
|
the state in such a way that it could possibly be a desired state for one
|
||||||
code is a generic producer-consumer situation with unlimited buffer capacity::
|
of the waiters. For example, the following code is a generic
|
||||||
|
producer-consumer situation with unlimited buffer capacity::
|
||||||
|
|
||||||
# Consume one item
|
# Consume one item
|
||||||
cv.acquire()
|
with cv:
|
||||||
while not an_item_is_available():
|
while not an_item_is_available():
|
||||||
cv.wait()
|
cv.wait()
|
||||||
get_an_available_item()
|
get_an_available_item()
|
||||||
cv.release()
|
|
||||||
|
|
||||||
# Produce one item
|
# Produce one item
|
||||||
cv.acquire()
|
with cv:
|
||||||
make_an_item_available()
|
make_an_item_available()
|
||||||
cv.notify()
|
|
||||||
cv.release()
|
|
||||||
|
|
||||||
To choose between :meth:`notify` and :meth:`notify_all`, consider whether one
|
The ``while`` loop checking for the application's condition is necessary
|
||||||
state change can be interesting for only one or several waiting threads. E.g.
|
because :meth:`~Condition.wait` can return after an arbitrary long time,
|
||||||
in a typical producer-consumer situation, adding one item to the buffer only
|
and other threads may have exhausted the available items in between. This
|
||||||
needs to wake up one consumer thread.
|
is inherent to multi-threaded programming. The :meth:`~Condition.wait_for`
|
||||||
|
method can be used to automate the condition checking::
|
||||||
|
|
||||||
Note: Condition variables can be, depending on the implementation, subject
|
# Consume an item
|
||||||
to both spurious wakeups (when :meth:`wait` returns without a :meth:`notify`
|
with cv:
|
||||||
call) and stolen wakeups (when another thread acquires the lock before the
|
cv.wait_for(an_item_is_available)
|
||||||
awoken thread.) For this reason, it is always necessary to verify the state
|
get_an_available_item()
|
||||||
the thread is waiting for when :meth:`wait` returns and optionally repeat
|
|
||||||
the call as often as necessary.
|
|
||||||
|
|
||||||
|
To choose between :meth:`~Condition.notify` and :meth:`~Condition.notify_all`,
|
||||||
|
consider whether one state change can be interesting for only one or several
|
||||||
|
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)
|
.. class:: Condition(lock=None)
|
||||||
|
|
||||||
|
@ -626,12 +637,6 @@ the call as often as necessary.
|
||||||
held when called and is re-aquired on return. The predicate is evaluated
|
held when called and is re-aquired on return. The predicate is evaluated
|
||||||
with the lock held.
|
with the lock held.
|
||||||
|
|
||||||
Using this method, the consumer example above can be written thus::
|
|
||||||
|
|
||||||
with cv:
|
|
||||||
cv.wait_for(an_item_is_available)
|
|
||||||
get_an_available_item()
|
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
.. method:: notify(n=1)
|
.. method:: notify(n=1)
|
||||||
|
|
|
@ -138,6 +138,11 @@ Build
|
||||||
- Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined.
|
- Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined.
|
||||||
Based on patch from Hervé Coatanhay.
|
Based on patch from Hervé Coatanhay.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Issue #8799: Fix and improve the threading.Condition documentation.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.2.3 release candidate 2?
|
What's New in Python 3.2.3 release candidate 2?
|
||||||
===============================================
|
===============================================
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue