将锁迁移到TPL

Ear*_*ine 4 .net c# synchronization task-parallel-library

在正常的C#中我们写

int DoSomething(){/*...*/)};

lock(mutex)
{
    return DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

确保在所有情况下都mutex被释放.

但如果签名DoSomething改为

Task<int> DoSomeThingAsync(){/*...*/};
Run Code Online (Sandbox Code Playgroud)

是否有以下代码

return Task.Factory.StartNew(() =>
{
    Monitor.Enter(mutex);
    return DoSomethingAsync();
}).Unwrap().ContinueWith(t =>
{
    Monitor.Exit(mutex);
    return t;
}).Unwrap();
Run Code Online (Sandbox Code Playgroud)

做类似的事情?是否保证mutex在输入时释放?有没有更简单的方法呢?(我无法使用async关键字,所以请继续考虑TPL)

i3a*_*non 8

你不能Monitor以这种方式使用,因为它Monitor是线程仿射的,在你的情况下,任务和延续可能在不同的线程上运行.

要使用的适当同步机制是SemaphoreSlim(不是线程仿射)设置为1:

public SemaphoreSlim _semaphore = new SemaphoreSlim(1,1);

_semaphore.Wait();
return DoSomethingAsync().ContinueWith(t =>
{
    _semaphore.Release();
    return t.Result;
});
Run Code Online (Sandbox Code Playgroud)

只要你不使用的一个TaskContinuationOptionsOnlyOnFaultedOnlyOnCanceled任务已经完成,因此该信号可以保证被释放后的延续将始终运行.