3

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#

7
  • 2
    The async calls are independent between themselves. What is it that you are trying to achieve? Can you provide some more information please? Commented Feb 11, 2020 at 11:57
  • 2
    Why doesn't the code await for the method to complete? How is openAsync called? Is there a missing await perhaps? There's no need for any queues, that's how Tasks already work. Commented Feb 11, 2020 at 11:58
  • 1
    there are two main scenarios with async; 1) the caller worries about concurrency, and only calls methods appropriately, awaiting between them - usually from a single caller logical flow; 2) the type worries about concurrency, with logical queues (and often multiple parallel caller flows against the same instance); the first is much, much easier to implement and understand, and is by far the majority usage; the second is really quite hard; are you sure you need that? can you explain why you need that? it can be done, but ... it is a huge thing to explain and do Commented Feb 11, 2020 at 12:02
  • It is very difficult to answer this question. We do not know how classes are designed and where this method is located and where the callers are located and who is going to add entries to queue. Did you consider using Singleton class which has only this method and runs this method synchronously ? Commented Feb 11, 2020 at 12:14
  • it could also be a lot easier to implement this if it can be reduced to something like a semaphore-slim around access, so that only one concurrent caller is permitted (with any other concurrent callers waiting on the semaphore) Commented Feb 11, 2020 at 12:37

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.