Table of Contents

Class AsyncReentrantLock

Namespace
CryptoHives.Foundation.Threading.Async.Pooled
Assembly
CryptoHives.Foundation.Threading.dll

An experimental async lock that a nested call on the same logical async flow can re-acquire without deadlocking, unlike AsyncLock.

public sealed class AsyncReentrantLock
Inheritance
AsyncReentrantLock
Inherited Members

Remarks

Reentrancy is tracked through ExecutionContext, so an async method that awaits LockAsync(CancellationToken) and returns the releaser hides the hold from its caller, and the caller's next nested acquisition deadlocks. Releasing returns at once, but the lock stays held while nested holders such as fire-and-forget work are still running, until the last of them releases.

Constructors

AsyncReentrantLock(int, int)

Constructs a new AsyncReentrantLock.

public AsyncReentrantLock(int defaultDepthLocksCapacity = 4, int maxDepthLocksCapacity = 32)

Parameters

defaultDepthLocksCapacity int

The initial capacity of the depth table; it grows on demand up to maxDepthLocksCapacity.

maxDepthLocksCapacity int

The maximum nesting depth; a call that would nest deeper throws InvalidOperationException.

Exceptions

ArgumentOutOfRangeException

Thrown when either capacity is below DefaultDepthLocksCapacity, or defaultDepthLocksCapacity exceeds maxDepthLocksCapacity.

Fields

DefaultDepthLocksCapacity

The default initial capacity of the depth table, and the smallest capacity accepted.

public const int DefaultDepthLocksCapacity = 4

Field Value

int

MaxDepthLocksCapacity

The default maximum nesting depth.

public const int MaxDepthLocksCapacity = 32

Field Value

int

Properties

DepthsCreated

Gets the number of distinct nesting depths this instance has reached; at least 1. Diagnostic only.

public int DepthsCreated { get; }

Property Value

int

Methods

LockAsync(CancellationToken)

Asynchronously acquires the lock. A call nested inside a hold on the same logical flow acquires the next depth instead of deadlocking; concurrent siblings at the same depth serialize.

public ValueTask<AsyncReentrantLock.Releaser> LockAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

The cancellation token.

Returns

ValueTask<AsyncReentrantLock.Releaser>

A ValueTask<TResult> that completes when the lock is acquired. Dispose the returned releaser to release the lock.

Exceptions

OperationCanceledException

Thrown when cancellationToken is cancelled before the lock can be acquired.

InvalidOperationException

Thrown when the call would nest deeper than the maximum depth set at construction.

LockAsync(TimeSpan, CancellationToken)

Asynchronously acquires the lock, or throws if it cannot be acquired before the timeout elapses.

public ValueTask<AsyncReentrantLock.Releaser> LockAsync(TimeSpan timeout, CancellationToken cancellationToken = default)

Parameters

timeout TimeSpan

The maximum time to wait. Use InfiniteTimeSpan to wait indefinitely.

cancellationToken CancellationToken

The cancellation token used to cancel the wait.

Returns

ValueTask<AsyncReentrantLock.Releaser>

A ValueTask<TResult> that completes when the lock is acquired. Dispose the returned releaser to release the lock.

Exceptions

ArgumentOutOfRangeException

Thrown when timeout is negative and not equal to InfiniteTimeSpan.

TimeoutException

Thrown when the timeout elapses before the lock can be acquired.

OperationCanceledException

Thrown when cancellationToken is cancelled before the lock can be acquired.

InvalidOperationException

Thrown when the call would nest deeper than the maximum depth set at construction.

LockLeafAsync(CancellationToken)

Asynchronously acquires the lock at the same depth as LockAsync(CancellationToken), but without recording the hold for further nesting, which makes it cheaper.

public ValueTask<AsyncReentrantLock.Releaser> LockLeafAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

The cancellation token.

Returns

ValueTask<AsyncReentrantLock.Releaser>

A ValueTask<TResult> that completes when the lock is acquired. Dispose the returned releaser to release the lock.

Remarks

Use it only for innermost regions that never call back into this lock: a LockAsync(CancellationToken) or LockLeafAsync(CancellationToken) call made inside the hold deadlocks, as with AsyncLock.

Exceptions

OperationCanceledException

Thrown when cancellationToken is cancelled before the lock can be acquired.

InvalidOperationException

Thrown when the call would nest deeper than the maximum depth set at construction.

LockLeafAsync(TimeSpan, CancellationToken)

Asynchronously acquires the lock like LockLeafAsync(CancellationToken), or throws if it cannot be acquired before the timeout elapses.

public ValueTask<AsyncReentrantLock.Releaser> LockLeafAsync(TimeSpan timeout, CancellationToken cancellationToken = default)

Parameters

timeout TimeSpan

The maximum time to wait. Use InfiniteTimeSpan to wait indefinitely.

cancellationToken CancellationToken

The cancellation token used to cancel the wait.

Returns

ValueTask<AsyncReentrantLock.Releaser>

A ValueTask<TResult> that completes when the lock is acquired. Dispose the returned releaser to release the lock.

Remarks

Use it only for innermost regions that never call back into this lock: a LockAsync(CancellationToken) or LockLeafAsync(CancellationToken) call made inside the hold deadlocks, as with AsyncLock.

Exceptions

ArgumentOutOfRangeException

Thrown when timeout is negative and not equal to InfiniteTimeSpan.

TimeoutException

Thrown when the timeout elapses before the lock can be acquired.

OperationCanceledException

Thrown when cancellationToken is cancelled before the lock can be acquired.

InvalidOperationException

Thrown when the call would nest deeper than the maximum depth set at construction.