将锁迁移到TPL

时间:2014-11-12 22:39:47

标签: c# .net synchronization task-parallel-library

在正常的C#中我们写

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

lock(mutex)
{
    return DoSomething();
}

确保在所有情况下释放mutex

但如果DoSomething的签名改为

Task<int> DoSomeThingAsync(){/*...*/};

以下代码

return Task.Factory.StartNew(() =>
{
    Monitor.Enter(mutex);
    return DoSomethingAsync();
}).Unwrap().ContinueWith(t =>
{
    Monitor.Exit(mutex);
    return t;
}).Unwrap();
做类似的事情?是否保证在输入时释放mutex?有没有更简单的方法呢? (我无法使用async关键字,所以请继续考虑TPL)

1 个答案:

答案 0 :(得分:8)

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

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

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

_semaphore.Wait();
return DoSomethingAsync().ContinueWith(t =>
{
    _semaphore.Release();
    return t.Result;
});

只要您不使用其中一个TaskContinuationOptions,例如OnlyOnFaultedOnlyOnCanceled,就会在任务完成后继续运行,因此保证信号量被释放。