Issue #23484: Document differences between synchronization primitives of

threading and multiprocessing modules.

In multiprocessing, the name of the first parameter of the acquire methods is
"block", but "blocking" in threading.

This commit also improves documentation of Lock and RLock.

Patch by Davin Potts.
This commit is contained in:
Berker Peksag 2015-09-21 06:51:45 +03:00
commit 64c8befaed
1 changed files with 119 additions and 12 deletions

View File

@ -1129,10 +1129,15 @@ object -- see :ref:`multiprocessing-managers`.
.. class:: BoundedSemaphore([value]) .. class:: BoundedSemaphore([value])
A bounded semaphore object: a clone of :class:`threading.BoundedSemaphore`. A bounded semaphore object: a close analog of
:class:`threading.BoundedSemaphore`.
(On Mac OS X, this is indistinguishable from :class:`Semaphore` because A solitary difference from its close analog exists: its ``acquire`` method's
``sem_getvalue()`` is not implemented on that platform). first argument is named *block*, as is consistent with :meth:`Lock.acquire`.
.. note::
On Mac OS X, this is indistinguishable from :class:`Semaphore` because
``sem_getvalue()`` is not implemented on that platform.
.. class:: Condition([lock]) .. class:: Condition([lock])
@ -1148,26 +1153,128 @@ object -- see :ref:`multiprocessing-managers`.
A clone of :class:`threading.Event`. A clone of :class:`threading.Event`.
.. class:: Lock() .. class:: Lock()
A non-recursive lock object: a clone of :class:`threading.Lock`. A non-recursive lock object: a close analog of :class:`threading.Lock`.
Once a process or thread has acquired a lock, subsequent attempts to
acquire it from any process or thread will block until it is released;
any process or thread may release it. The concepts and behaviors of
:class:`threading.Lock` as it applies to threads are replicated here in
:class:`multiprocessing.Lock` as it applies to either processes or threads,
except as noted.
Note that :class:`Lock` is actually a factory function which returns an
instance of ``multiprocessing.synchronize.Lock`` initialized with a
default context.
:class:`Lock` supports the :term:`context manager` protocol and thus may be
used in :keyword:`with` statements.
.. method:: acquire(block=True, timeout=None)
Acquire a lock, blocking or non-blocking.
With the *block* argument set to ``True`` (the default), the method call
will block until the lock is in an unlocked state, then set it to locked
and return ``True``. Note that the name of this first argument differs
from that in :meth:`threading.Lock.acquire`.
With the *block* argument set to ``False``, the method call does not
block. If the lock is currently in a locked state, return ``False``;
otherwise set the lock to a locked state and return ``True``.
When invoked with a positive, floating-point value for *timeout*, block
for at most the number of seconds specified by *timeout* as long as
the lock can not be acquired. Invocations with a negative value for
*timeout* are equivalent to a *timeout* of zero. Invocations with a
*timeout* value of ``None`` (the default) set the timeout period to
infinite. Note that the treatment of negative or ``None`` values for
*timeout* differs from the implemented behavior in
:meth:`threading.Lock.acquire`. The *timeout* argument has no practical
implications if the *block* argument is set to ``False`` and is thus
ignored. Returns ``True`` if the lock has been acquired or ``False`` if
the timeout period has elapsed.
.. method:: release()
Release a lock. This can be called from any process or thread, not only
the process or thread which originally acquired the lock.
Behavior is the same as in :meth:`threading.Lock.release` except that
when invoked on an unlocked lock, a :exc:`ValueError` is raised.
.. class:: RLock() .. class:: RLock()
A recursive lock object: a clone of :class:`threading.RLock`. A recursive lock object: a close analog of :class:`threading.RLock`. A
recursive lock must be released by the process or thread that acquired it.
Once a process or thread has acquired a recursive lock, the same process
or thread may acquire it again without blocking; that process or thread
must release it once for each time it has been acquired.
Note that :class:`RLock` is actually a factory function which returns an
instance of ``multiprocessing.synchronize.RLock`` initialized with a
default context.
:class:`RLock` supports the :term:`context manager` protocol and thus may be
used in :keyword:`with` statements.
.. method:: acquire(block=True, timeout=None)
Acquire a lock, blocking or non-blocking.
When invoked with the *block* argument set to ``True``, block until the
lock is in an unlocked state (not owned by any process or thread) unless
the lock is already owned by the current process or thread. The current
process or thread then takes ownership of the lock (if it does not
already have ownership) and the recursion level inside the lock increments
by one, resulting in a return value of ``True``. Note that there are
several differences in this first argument's behavior compared to the
implementation of :meth:`threading.RLock.acquire`, starting with the name
of the argument itself.
When invoked with the *block* argument set to ``False``, do not block.
If the lock has already been acquired (and thus is owned) by another
process or thread, the current process or thread does not take ownership
and the recursion level within the lock is not changed, resulting in
a return value of ``False``. If the lock is in an unlocked state, the
current process or thread takes ownership and the recursion level is
incremented, resulting in a return value of ``True``.
Use and behaviors of the *timeout* argument are the same as in
:meth:`Lock.acquire`. Note that some of these behaviors of *timeout*
differ from the implemented behaviors in :meth:`threading.RLock.acquire`.
.. method:: release()
Release a lock, decrementing the recursion level. If after the
decrement the recursion level is zero, reset the lock to unlocked (not
owned by any process or thread) and if any other processes or 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 process or
thread.
Only call this method when the calling process or thread owns the lock.
An :exc:`AssertionError` is raised if this method is called by a process
or thread other than the owner or if the lock is in an unlocked (unowned)
state. Note that the type of exception raised in this situation
differs from the implemented behavior in :meth:`threading.RLock.release`.
.. class:: Semaphore([value]) .. class:: Semaphore([value])
A semaphore object: a clone of :class:`threading.Semaphore`. A semaphore object: a close analog of :class:`threading.Semaphore`.
A solitary difference from its close analog exists: its ``acquire`` method's
first argument is named *block*, as is consistent with :meth:`Lock.acquire`.
.. note:: .. note::
The :meth:`acquire` and :meth:`wait` methods of each of these types
treat negative timeouts as zero timeouts. This differs from
:mod:`threading` where, since version 3.2, the equivalent
:meth:`acquire` methods treat negative timeouts as infinite
timeouts.
On Mac OS X, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with On Mac OS X, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with
a timeout will emulate that function's behavior using a sleeping loop. a timeout will emulate that function's behavior using a sleeping loop.