Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.13] gh-70795: Rework RLock documentation (GH-103853) #119436

Merged
merged 1 commit into from
May 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 51 additions & 24 deletions Doc/library/threading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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.
Expand All @@ -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.

Expand Down
Loading