stouputils.lock.re_entrant module#

class RLockFifo(
name: str,
timeout: float | None = None,
blocking: bool = True,
check_interval: float = 0.05,
fifo: bool = True,
fifo_stale_timeout: float | None = None,
)[source]#

Bases: LockFifo

A re-entrant cross-process lock backed by a file.

This lock is re-entrant for the same owner, where owner identity is the tuple (path, pid, thread_id). Repeated calls to acquire() by the same owner increment an internal counter; only the final release() will release the underlying file lock managed by LockFifo.

Key behaviour:
  • Owner identity: (path, pid, thread_id)

  • Reentrancy applies only within the same thread of the same process. Other threads or processes will block (or raise LockTimeoutError) according to the lock’s timeout and blocking parameters.

  • Implemented on top of LockFifo and shares its constructor parameters and error semantics.

Parameters:
  • name (str) – Lock filename or path. If a simple name is given, it is created in the system temporary directory.

  • timeout (float | None) – Seconds to wait for the lock. None means block indefinitely.

  • blocking (bool) – Whether to block until acquired (subject to timeout).

  • check_interval (float) – Interval between lock attempts, in seconds.

  • fifo (bool) – Whether to enforce Fifo ordering (default: True).

  • fifo_stale_timeout (float | None) – Seconds after which a ticket is considered stale; if None the lock’s timeout value will be used.

Raises:
  • LockTimeoutError – If the lock could not be acquired within the timeout (LockError & TimeoutError subclass)

  • LockError – On unexpected locking errors. (RunTimeError subclass)

Examples

>>> with RLockFifo("my.lock", timeout=5):
...     # critical section
...     pass
>>> lock = RLockFifo("my.lock")
>>> lock.acquire()
>>> lock.acquire()  # re-entrant acquire by same thread/process
>>> lock.release()
>>> lock.release()  # underlying lock released here
>>> # Reentrancy with Fifo enabled should not create multiple tickets
>>> lock = RLockFifo("my_r.lock", fifo=True, timeout=1)
>>> lock.acquire()
>>> lock.acquire()
>>> lock.release()
>>> lock.release()
>>> # Cleanup behaviour: after closing a re-entrant lock the queue should be removed when empty
>>> import tempfile, os
>>> tmp = tempfile.mkdtemp()
>>> p = tmp + "/rlock"
>>> r = RLockFifo(p, fifo=True, timeout=1)
>>> r.acquire(); r.acquire(); r.release(); r.release(); r.close()
>>> os.path.exists(p + ".queue")
False
owners: ClassVar[dict[tuple[str, int, int], int]] = {}#

Mapping of owner keys to re-entrant acquisition counts.

acquire(
timeout: float | None = None,
blocking: bool | None = None,
check_interval: float | None = None,
) None[source]#

Acquire the lock with re-entrancy for the same owner.

If the current owner (same self.key) already holds the lock, the internal counter is incremented and the underlying file lock is not re-acquired. Otherwise this delegates to LockFifo.acquire().

_abc_impl = <_abc._abc_data object>#
release() None[source]#

Release the lock for this owner.

Decrements the re-entrant counter for the current owner and only when the counter reaches zero the underlying LockFifo is released.