summaryrefslogtreecommitdiff
path: root/Doc/library/threading.rst
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2012-04-10 22:24:05 +0200
committerAntoine Pitrou <solipsis@pitrou.net>2012-04-10 22:24:05 +0200
commitad404821c79856afb47554ff40fda6500e03d230 (patch)
treee56f29daa7b732010b55a6cf8456a3b8afe25969 /Doc/library/threading.rst
parent2223500cbdf142bfb336f579377874117adc55c1 (diff)
downloadcpython-ad404821c79856afb47554ff40fda6500e03d230.tar.gz
Issue #8799: Fix and improve the threading.Condition documentation.
Diffstat (limited to 'Doc/library/threading.rst')
-rw-r--r--Doc/library/threading.rst113
1 files changed, 59 insertions, 54 deletions
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index 0738e22776..2fccdba4f7 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -503,62 +503,73 @@ Condition Objects
-----------------
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
-several condition variables must share the same lock.)
-
-A condition variable has :meth:`acquire` and :meth:`release` methods that call
-the corresponding methods of the associated lock. It also has a :meth:`wait`
-method, and :meth:`notify` and :meth:`notify_all` methods. These three must only
-be called when the calling thread has acquired the lock, otherwise a
-:exc:`RuntimeError` is raised.
-
-The :meth:`wait` method releases the lock, and then blocks until it is awakened
-by a :meth:`notify` or :meth:`notify_all` call for the same condition variable in
-another thread. Once awakened, it 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
-variable, if any are waiting. The :meth:`notify_all` method wakes up all threads
-waiting for the condition variable.
-
-Note: the :meth:`notify` and :meth:`notify_all` methods don't release the lock;
-this means that the thread or threads awakened will not return from their
-:meth:`wait` call immediately, but only when the thread that called
-:meth:`notify` or :meth:`notify_all` finally relinquishes ownership of the lock.
-
-Tip: the typical programming style using condition variables uses the lock to
+passed in or one will be created by default. Passing one in is useful when
+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 obeys the :term:`context manager` protocol: using the
+``with`` statement acquires the associated lock for the duration of the
+enclosed block. The :meth:`~Condition.acquire` and :meth:`~Condition.release`
+methods also call the corresponding methods of the associated lock.
+
+Other methods must be called with the associated lock held. The
+:meth:`~Condition.wait` method releases the lock, and then blocks until
+another thread awakens it by calling :meth:`~Condition.notify` or
+: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:`~Condition.notify` method wakes up one of the threads waiting for
+the condition variable, if any are waiting. The :meth:`~Condition.notify_all`
+method wakes up all threads waiting for the condition variable.
+
+Note: the :meth:`~Condition.notify` and :meth:`~Condition.notify_all` methods
+don't release the lock; this means that the thread or threads awakened will
+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:`wait` repeatedly until they see the
-desired state, while threads that modify the state call :meth:`notify` or
-:meth:`notify_all` when they change the state in such a way that it could
-possibly be a desired state for one of the waiters. For example, the following
-code is a generic producer-consumer situation with unlimited buffer capacity::
+particular change of state call :meth:`~Condition.wait` repeatedly until they
+see the desired state, while threads that modify the state call
+:meth:`~Condition.notify` or :meth:`~Condition.notify_all` when they change
+the state in such a way that it could possibly be a desired state for one
+of the waiters. For example, the following code is a generic
+producer-consumer situation with unlimited buffer capacity::
# Consume one item
- cv.acquire()
- while not an_item_is_available():
- cv.wait()
- get_an_available_item()
- cv.release()
+ with cv:
+ while not an_item_is_available():
+ cv.wait()
+ get_an_available_item()
# Produce one item
- cv.acquire()
- make_an_item_available()
- cv.notify()
- cv.release()
+ with cv:
+ make_an_item_available()
+
+The ``while`` loop checking for the application's condition is necessary
+because :meth:`~Condition.wait` can return after an arbitrary long time,
+and other threads may have exhausted the available items in between. This
+is inherent to multi-threaded programming. The :meth:`~Condition.wait_for`
+method can be used to automate the condition checking::
+
+ # Consume an item
+ with cv:
+ cv.wait_for(an_item_is_available)
+ get_an_available_item()
-To choose between :meth:`notify` and :meth:`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.
+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.
-Note: Condition variables can be, depending on the implementation, subject
-to both spurious wakeups (when :meth:`wait` returns without a :meth:`notify`
-call) and stolen wakeups (when another thread acquires the lock before the
-awoken thread.) For this reason, it is always necessary to verify the state
-the thread is waiting for when :meth:`wait` returns and optionally repeat
-the call as often as necessary.
+Interface
+^^^^^^^^^
.. 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
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
.. method:: notify(n=1)