使用嵌套的异步调用进行锁定

我正在开发一个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 } }