At any time, I can receive a method call that will require a long-running operation to satisfy.
There are several of these methods. Because they share a resource, it's important that they don't run concurrently - each should run in sequence.
Normally, I'd simply make the calls in sequence:
var result1 = await Foo1Async();
var result2 = await Foo2Async();
However, in this case, the method calls to me are asynchronous:
void Bar1()
{
var result = await Foo1Async();
// ...
}
void Bar2()
{
var result = await Foo2Async();
// ...
}
I think I need to use Task.ContinueWith
, and have come up with this:
readonly object syncLock = new Object();
private Task currentOperationTask = TaskUtilities.CompletedTask;
public Task<TResult> EnqueueOperation<TResult>(Func<Task<TResult>> continuationFunction)
{
lock (this.syncLock)
{
var operation = this.currentOperationTask.ContinueWith(predecessor => continuationFunction()).Unwrap();
this.currentOperationTask = operation;
return operation;
}
}
And I use it like this:
void Bar1()
{
var result = await EnqueueOperation(() => Foo1Async());
// ...
}
void Bar2()
{
var result = await EnqueueOperation(() => Foo2Async());
// ...
}
Is this the right way to approach this problem? Are there any pitfalls I should be aware of?
Your code will work fine, I think this is a reasonable way to solve the problem.
A simpler approach to do this would be to use AsyncLock
from Nito AsyncEx:
private readonly AsyncLock asyncLock = new AsyncLock();
public async Task<TResult> EnqueueOperation<TResult>(
Func<Task<TResult>> continuationFunction)
{
using (await asyncLock.LockAsync())
{
return await continuationFunction();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With