使用嵌套的异步调用进行锁定
我正在开发一个multithreadingWindowsPhone8应用程序,该应用程序在异步方法中具有关键部分。
有没有人知道在C#中正确使用信号量/互斥量的方法,其中你使用嵌套的异步调用,其中内部方法可能获取它已经获取了调用堆栈的相同锁? 我认为SemaphoreSlim可能是答案,但看起来它会导致死锁。
public class Foo { SemaphoreSlim _lock = new SemaphoreSlim(1); public async Task Bar() { await _lock.WaitAsync(); await BarInternal(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); // deadlock // DO work _lock.Release(); } }
递归锁是一个非常糟糕的主意 (IMO;链接到我自己的博客)。 对于async
代码尤其如此。 很难让async
兼容的递归锁工作。 我在这里有一个概念validation,但公平警告:我不建议在生产中使用此代码,此代码不会被转换为AsyncEx,并且未经过全面测试。
你应该做的是重构你的代码,如@svick所述。 像这样的东西:
public async Task Bar() { await _lock.WaitAsync(); await BarInternal_UnderLock(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); await BarInternal_UnderLock(); _lock.Release(); } private async Task BarInternal_UnderLock() { // DO work }
这就是我在这种情况下所做的事情(仍然,我没有任务经验,所以不要打败我;-)
因此,基本上您已将实际实现移至非锁定方法,并在获取锁定的所有方法中使用这些方法。
public class Foo { SemaphoreSlim _lock = new SemaphoreSlim(1); public async Task Bar() { await _lock.WaitAsync(); await BarNoLock(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); // no deadlock await BarNoLock(); _lock.Release(); } private async Task BarNoLock() { // do the work } }