Migrating lock to TPL

别等时光非礼了梦想. 提交于 2019-12-23 12:08:33

问题


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)


回答1:


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.



来源:https://stackoverflow.com/questions/26898058/migrating-lock-to-tpl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!