Reputation: 31
I have a method that looks like
public async Task<OpenResult> openAsync()
I want to do something like if there is a current call to openAsync in the process of getting executed, I would like to place any calls to OpenAsync be added to a queue.
When the first call completes, I want to complete all the ones in the queue with the result of the first call.
What’s the way to achieve this in C#
Upvotes: 3
Views: 199
Reputation: 1062855
Usually, this kind of detail is left to the caller, i.e. by making the caller await
appropriately and only call methods when they should call methods. However, if you must do this, one simple way is via a semaphore; consider:
class HazProtected
{
private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
public async Task<OpenResult> OpenAsync(CancellationToken cancellationToken = default)
{
await _lock.WaitAsync(cancellationToken);
try
{
return await DoOpenAsync(cancellationToken);
}
finally
{
_lock.Release();
}
}
private async Task<OpenResult> DoOpenAsync(CancellationToken cancellationToken)
{
// ... your real code here
}
}
The code in OpenAsync
ensures that only one concurrent async caller can be attempting to open it at a time. When there is a conflict, callers are held asynchronously until the semaphore can be acquired. There is a complication, though; SempahoreSlim
has some known problems on .NET Framework (resolved in .NET Core) when there are both asynchronous and synchronous semaphore acquisitions at the same time - which can lead to a spiral of death.
In more complex scenarios, it is possible to write your own queue of pending callers; this is a very very exotic scenario and should usually not be attempted unless you understand exactly why you're doing it!
Upvotes: 2