-1

What I mean is, say we have an async method Task<string> CalculateSha256(string s). Is it possible, that calls from thread #1 and thread #2 are executed consecutively as oposed to being executed concurrently, without threads #1 and #2 knowing anything about each other? For example, I have a controller,

public async Task<string> Get(string value)
{
    return await CalculateSha256(value);
}

and I want two different requests to access the chunk of code that's responsible for calculation (CalculateSha256) consecutively.

YuvShap
  • 3,825
  • 2
  • 10
  • 24
nicks
  • 2,161
  • 8
  • 49
  • 101
  • this is a different question, because these two threads should not await the **same** task, however, one should wait for the end of another, in order to continue. – nicks Sep 17 '17 at 13:28
  • Can you show what you're trying to achieve? Perhaps Task's `ContinueWith()` may be an answer? Or `TaskCompletionSource` class? – orhtej2 Sep 17 '17 at 13:30

1 Answers1

4

You need to synchronize the access to CalculateSha256 method that only one thread will execute it at a time.
Since lock statement does not play nicely with async you can use SemaphoreSlim class.

Just add it as a static field to your controller:

private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);

And use WaitAsync method in your action (and do not forget to release it when you finish, using finally block):

public async Task<string> Get(string value)
{
    await _semaphoreSlim.WaitAsync();
    try
    {
        return await CalculateSha256(value);
    }
    finally
    { 
        _semaphoreSlim.Release();
    }
}

If you find this approach useful and you do not like to reapeat the try finally block you can create a base controller class with a protected generic helper:

protected async Task<T> GetConsecutively(Func<Task<T>> taskFactory)
{
    await _semaphoreSlim.WaitAsync();
    try
    {
        return await taskFactory();
    }
    finally
    { 
        _semaphoreSlim.Release();
    }
}

And modify Get method to pass a lambda expression to it:

public async Task<string> Get(string value)
{
    return await GetConsecutively(() => CalculateSha256(value));
}

Or alternatively use Stephen Cleary's AsyncLock instead of SemaphoreSlim which supports a high level API closer to the lock statement:

private static readonly AsyncLock _asyncLock = new AsyncLock();

public async Task<string> Get(string value)
{
    //Notice the use of using block
    //instead of try and finally 
    using(await _asyncLock.LockAsync())
    {
        return await CalculateSha256(value);
    }
}
YuvShap
  • 3,825
  • 2
  • 10
  • 24