gh-70795: Rework RLock documentation (#103853)

Attempted to simultaneously reduce verbosity, while more descriptively
describing behavior.

Fix links (RLock acquire/release previously linking to Lock
acquire/release, seems like bad copy pasta).

Add a seealso for with-locks.

Switch section to use bullet points.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
uıɐɾ ʞ ʇɐɯɐs 2024-05-22 13:15:11 -07:00 committed by GitHub
parent c9073eb1a9
commit 2fbea81d64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 51 additions and 24 deletions

View File

@ -598,14 +598,25 @@ and "recursion level" in addition to the locked/unlocked state used by primitive
locks. In the locked state, some thread owns the lock; in the unlocked state,
no thread owns it.
To lock the lock, a thread calls its :meth:`~RLock.acquire` method; this
returns once the thread owns the lock. To unlock the lock, a thread calls
its :meth:`~Lock.release` method. :meth:`~Lock.acquire`/:meth:`~Lock.release`
call pairs may be nested; only the final :meth:`~Lock.release` (the
:meth:`~Lock.release` of the outermost pair) resets the lock to unlocked and
allows another thread blocked in :meth:`~Lock.acquire` to proceed.
Threads call a lock's :meth:`~RLock.acquire` method to lock it,
and its :meth:`~Lock.release` method to unlock it.
Reentrant locks also support the :ref:`context management protocol <with-locks>`.
.. note::
Reentrant locks support the :ref:`context management protocol <with-locks>`,
so it is recommended to use :keyword:`with` instead of manually calling
:meth:`~RLock.acquire` and :meth:`~RLock.release`
to handle acquiring and releasing the lock for a block of code.
RLock's :meth:`~RLock.acquire`/:meth:`~RLock.release` call pairs may be nested,
unlike Lock's :meth:`~Lock.acquire`/:meth:`~Lock.release`. Only the final
:meth:`~RLock.release` (the :meth:`~Lock.release` of the outermost pair) resets
the lock to an unlocked state and allows another thread blocked in
:meth:`~RLock.acquire` to proceed.
:meth:`~RLock.acquire`/:meth:`~RLock.release` must be used in pairs: each acquire
must have a release in the thread that has acquired the lock. Failing to
call release as many times the lock has been acquired can lead to deadlock.
.. class:: RLock()
@ -624,25 +635,41 @@ Reentrant locks also support the :ref:`context management protocol <with-locks>`
Acquire a lock, blocking or non-blocking.
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.
.. seealso::
When invoked with the *blocking* argument set to ``True``, do the same thing as when
called without arguments, and return ``True``.
:ref:`Using RLock as a context manager <with-locks>`
Recommended over manual :meth:`!acquire` and :meth:`release` calls
whenever practical.
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``.
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.
When invoked with the *blocking* argument set to ``True`` (the default):
* If no thread owns the lock, acquire the lock and return immediately.
* If another thread owns the lock, block until we are able to acquire
lock, or *timeout*, if set to a positive float value.
* If the same thread owns the lock, acquire the lock again, and
return immediately. This is the difference between :class:`Lock` and
:class:`!RLock`; :class:`Lock` handles this case the same as the previous,
blocking until the lock can be acquired.
When invoked with the *blocking* argument set to ``False``:
* If no thread owns the lock, acquire the lock and return immediately.
* If another thread owns the lock, return immediately.
* If the same thread owns the lock, acquire the lock again and return
immediately.
In all cases, if the thread was able to acquire the lock, return ``True``.
If the thread was unable to acquire the lock (i.e. if not blocking or
the timeout was reached) return ``False``.
If called multiple times, failing to call :meth:`~RLock.release` as many times
may lead to deadlock. Consider using :class:`!RLock` as a context manager rather than
calling acquire/release directly.
.. versionchanged:: 3.2
The *timeout* parameter is new.
@ -658,7 +685,7 @@ Reentrant locks also support the :ref:`context management protocol <with-locks>`
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.
not acquired.
There is no return value.