AsyncReaderWriterLock Class
Definition
- Assembly
- Bodu.Core.dll
- Package
- Bodu.Core 1.0.1
Provides an asynchronous, writer-preferring reader/writer lock whose acquisitions can be awaited without blocking a thread.
public sealed class AsyncReaderWriterLock : IDisposable
- Inheritance
-
AsyncReaderWriterLock
- Implements
- Inherited Members
- Extension Methods
Examples
private readonly AsyncReaderWriterLock _lock = new();
// Readers run concurrently with one another.
async Task<int> CountAsync()
{
using (await _lock.ReaderAsync())
return _cache.Count;
}
// A writer runs exclusively, excluding all readers for its duration.
async Task SetAsync(string key, int value)
{
using (await _lock.WriterAsync())
_cache[key] = value;
}
Remarks
AsyncReaderWriterLock permits any number of concurrent readers or a single exclusive writer. Read
access is acquired with ReaderAsync() and write access with WriterAsync(); both return
a AsyncReaderWriterLock.Releaser whose disposal releases the corresponding access, typically scoped with a using
statement.
Fairness. The lock is writer-preferring: while a writer is active or queued, newly arriving readers wait, and queued writers are granted in strict FIFO order. When a writer releases and no writer is queued, all waiting readers are admitted together (batch admission). This prevents writer starvation, but a sustained stream of writers can starve readers; choose this lock only when that trade-off is acceptable.
Reentrancy and upgrade. The lock is not reentrant and provides no upgradeable read mode. A caller must never acquire write access while already holding read access (or vice versa) on the same flow: doing so deadlocks, because the second acquisition waits for access the same flow already holds. To transition from reading to writing, release the read access first, then acquire the write access and re-validate state, accepting that the gap is not atomic.
Cancellation. Following the package-wide rule, access that can be granted immediately is granted even when the supplied token is already canceled; the token only cancels an acquisition that must queue, and cancellation removes only the calling waiter.
Continuations and disposal. All waiter completion sources use RunContinuationsAsynchronously, so releasing threads never run waiter continuations inline while holding the internal gate. Disposing the lock faults any still-waiting acquisition with ObjectDisposedException; dispose only when no acquisitions are expected to be granted afterwards.
Releaser ownership. Each AsyncReaderWriterLock.Releaser is idempotent: disposing it more than once (including copies of the same value) releases the access exactly once, so accidental double-disposal cannot corrupt the reader count or grant overlapping access.
Constructors
AsyncReaderWriterLock()
Initializes a new instance of the AsyncReaderWriterLock class in the released state.
public AsyncReaderWriterLock()
Methods
Dispose()
Releases the resources used by the lock. Any callers still waiting observe an ObjectDisposedException.
public void Dispose()
ReaderAsync()
Asynchronously acquires shared (read) access.
public ValueTask<AsyncReaderWriterLock.Releaser> ReaderAsync()
Returns
- ValueTask<AsyncReaderWriterLock.Releaser>
A ValueTask<TResult> yielding a AsyncReaderWriterLock.Releaser whose disposal releases read access.
Exceptions
- ObjectDisposedException
The lock has been disposed.
ReaderAsync(CancellationToken)
Asynchronously acquires shared (read) access, observing a cancellation request while waiting.
public ValueTask<AsyncReaderWriterLock.Releaser> ReaderAsync(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationTokenA token used to cancel the pending acquisition.
Returns
- ValueTask<AsyncReaderWriterLock.Releaser>
A ValueTask<TResult> yielding a AsyncReaderWriterLock.Releaser whose disposal releases read access.
Remarks
The returned ValueTask<TResult> must be awaited exactly once. Read access that can be granted
immediately is granted even when cancellationToken is already canceled; the token only
cancels an acquisition that must queue.
Exceptions
- ObjectDisposedException
The lock has been disposed.
- OperationCanceledException
cancellationTokenwas canceled before access was acquired.
WriterAsync()
Asynchronously acquires exclusive (write) access.
public ValueTask<AsyncReaderWriterLock.Releaser> WriterAsync()
Returns
- ValueTask<AsyncReaderWriterLock.Releaser>
A ValueTask<TResult> yielding a AsyncReaderWriterLock.Releaser whose disposal releases write access.
Exceptions
- ObjectDisposedException
The lock has been disposed.
WriterAsync(CancellationToken)
Asynchronously acquires exclusive (write) access, observing a cancellation request while waiting.
public ValueTask<AsyncReaderWriterLock.Releaser> WriterAsync(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationTokenA token used to cancel the pending acquisition.
Returns
- ValueTask<AsyncReaderWriterLock.Releaser>
A ValueTask<TResult> yielding a AsyncReaderWriterLock.Releaser whose disposal releases write access.
Remarks
The returned ValueTask<TResult> must be awaited exactly once. Write access that can be granted
immediately is granted even when cancellationToken is already canceled; the token only
cancels an acquisition that must queue.
Exceptions
- ObjectDisposedException
The lock has been disposed.
- OperationCanceledException
cancellationTokenwas canceled before access was acquired.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |