在正常的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)
答案 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
,例如OnlyOnFaulted
或OnlyOnCanceled
,就会在任务完成后继续运行,因此保证信号量被释放。