AsyncSemaphore Class
Definition
- Assembly
- Bodu.Core.dll
- Package
- Bodu.Core 1.0.1
Provides a lightweight asynchronous counting semaphore that admits a bounded number of concurrent holders and releases waiters in strict first-in, first-out order.
public sealed class AsyncSemaphore
- Inheritance
-
AsyncSemaphore
- Inherited Members
- Extension Methods
Examples
private readonly AsyncSemaphore _throttle = new(initialCount: 4);
public async Task DownloadAsync(Uri uri)
{
using (await _throttle.LockAsync())
{
// At most four downloads run concurrently.
await HttpGetAsync(uri);
}
}
Remarks
AsyncSemaphore is a queue-based asynchronous analogue of SemaphoreSlim. Callers await
WaitAsync() to consume a permit and call Release() to return one. The convenience
method LockAsync() pairs a wait with a disposable AsyncSemaphore.Releaser so a permit can be scoped
with a using statement.
Unlike SemaphoreSlim, waiters are released in strict FIFO order: the longest-waiting caller is always satisfied first. Each waiter is represented by a TaskCompletionSource<TResult> created with RunContinuationsAsynchronously, so a thread calling Release() is never hijacked to run a waiter's continuation inline. The type owns no operating-system handle and therefore does not implement IDisposable.
Cancellation follows the package-wide rule: an available permit is taken even when the supplied token is already canceled. A token only cancels a wait that must queue.
Release(int) first hands permits directly to queued waiters in FIFO order and only stores the remainder as available permits. Permits transferred to waiters never appear in CurrentCount, and the configured maximum applies only to the stored available count after queued waiters have been satisfied. The bound is validated before any permit is granted, so a release that would exceed the maximum throws InvalidOperationException without granting any waiter or changing CurrentCount.
Constructors
AsyncSemaphore(int)
Initializes a new instance of the AsyncSemaphore class with the specified number of permits and no upper bound on the permit count.
public AsyncSemaphore(int initialCount)
Parameters
initialCountintThe initial number of permits available.
Exceptions
- ArgumentOutOfRangeException
initialCountis negative.
AsyncSemaphore(int, int)
Initializes a new instance of the AsyncSemaphore class with the specified number of permits and maximum permit count.
public AsyncSemaphore(int initialCount, int maxCount)
Parameters
initialCountintThe initial number of permits available.
maxCountintThe maximum number of permits the semaphore can hold.
Exceptions
- ArgumentOutOfRangeException
initialCountis negative,maxCountis less than one, orinitialCountis greater thanmaxCount.
Properties
CurrentCount
Gets the number of permits currently available.
public int CurrentCount { get; }
Property Value
- int
The number of permits that can be taken without waiting.
Methods
LockAsync()
Asynchronously takes a permit and returns a disposable releaser that returns it when disposed.
public ValueTask<AsyncSemaphore.Releaser> LockAsync()
Returns
- ValueTask<AsyncSemaphore.Releaser>
A ValueTask<TResult> yielding a AsyncSemaphore.Releaser whose disposal returns the permit.
LockAsync(CancellationToken)
Asynchronously takes a permit and returns a disposable releaser that returns it when disposed, observing a cancellation request while waiting.
public ValueTask<AsyncSemaphore.Releaser> LockAsync(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationTokenA token used to cancel the pending wait.
Returns
- ValueTask<AsyncSemaphore.Releaser>
A ValueTask<TResult> yielding a AsyncSemaphore.Releaser whose disposal returns the permit.
Exceptions
- OperationCanceledException
cancellationTokenwas canceled before a permit was taken.
Release()
Returns a single permit to the semaphore, releasing the next waiter if one is queued.
public void Release()
Exceptions
- InvalidOperationException
Releasing would raise the permit count above the configured maximum.
Release(int)
Returns the specified number of permits to the semaphore, releasing queued waiters in FIFO order.
public void Release(int releaseCount)
Parameters
releaseCountintThe number of permits to return.
Exceptions
- ArgumentOutOfRangeException
releaseCountis less than one.- InvalidOperationException
Releasing would raise the permit count above the configured maximum. The release is atomic: when this exception is thrown, no waiter has been granted and CurrentCount is unchanged.
WaitAsync()
Asynchronously waits to take a permit.
public ValueTask WaitAsync()
Returns
Examples
// Manual permit management; pair every WaitAsync with a Release in a finally block.
await _throttle.WaitAsync();
try
{
await DoWorkAsync();
}
finally
{
_throttle.Release();
}
Remarks
The returned ValueTask must be awaited exactly once.
WaitAsync(CancellationToken)
Asynchronously waits to take a permit, observing a cancellation request while waiting.
public ValueTask WaitAsync(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationTokenA token used to cancel the pending wait.
Returns
Remarks
The returned ValueTask must be awaited exactly once. An available permit is taken even when
cancellationToken is already canceled; the token only cancels a wait that must queue, and
cancellation removes only the calling waiter from the queue.
Exceptions
- OperationCanceledException
cancellationTokenwas canceled before a permit was taken.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |