Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Migrating lock to TPL

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)

like image 464
Earth Engine Avatar asked Feb 11 '23 14:02

Earth Engine


1 Answers

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.

like image 66
i3arnon Avatar answered Feb 15 '23 11:02

i3arnon