In normal C# we write
int DoSomething(){/*...*/)};
lock(mutex)
{
return DoSomething();
}
to ensure in all cases the mutex is released.
But if the signature of DoSomething changed to
Task<int> DoSomeThingAsync(){/*...*/};
Does the following code
return Task.Factory.StartNew(() =>
{
Monitor.Enter(mutex);
return DoSomethingAsync();
}).Unwrap().ContinueWith(t =>
{
Monitor.Exit(mutex);
return t;
}).Unwrap();
do similar things? Is it guaranteed to release the mutex whenever it was entered? Are there any simpler way to do so? (I am not able to use the async keyword so keep thinking in TPL only)
You can't use Monitor in that way because Monitor is thread-affine and in your case the task and continuation may run on different threads.
The appropriate synchronization mechanism to use is a SemaphoreSlim (which isn't thread-affine) set to 1:
public SemaphoreSlim _semaphore = new SemaphoreSlim(1,1);
_semaphore.Wait();
return DoSomethingAsync().ContinueWith(t =>
{
_semaphore.Release();
return t.Result;
});
As long as you don't use one of the TaskContinuationOptions such as OnlyOnFaulted or OnlyOnCanceled the continuation would always run after the task has completed and so the semaphore is guaranteed to be released.
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