使用嵌套异步调用锁定
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用嵌套异步调用锁定相关的知识,希望对你有一定的参考价值。
我正在研究多线程WindowsPhone8应用程序,该应用程序在异步方法中具有关键部分。
有人知道在嵌套嵌套异步调用中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();
}
}
递归锁是really bad idea(IMO;链接是我自己的博客)。对于async
代码,这是尤其是 true。要使async
兼容的递归锁起作用是很困难的。我有一个proof-of-concept here,但有一个合理的警告:我确实建议在生产中使用此代码,[
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
}
}
System.Threading.ReaderWriterLockSlim
(doc):ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
async Task Bar()
{
try
{
_lock.EnterReadLock();
await BarInternal();
}
finally
{
if (_lock.IsReadLockHeld)
_lock.ExitReadLock();
}
}
async Task BarInternal()
{
try
{
_lock.EnterReadLock();
await Task.Delay(1000);
}
finally
{
if (_lock.IsReadLockHeld)
_lock.ExitReadLock();
}
}
仍然要对递归非常小心,因为很难控制哪个线程获得了锁定以及何时获得锁定。问题中的代码将导致死锁,因为它尝试两次获取锁,例如:
await _lock.WaitAsync(); await _lock.WaitAsync(); --> Will result in exception.
虽然在ReaderWriterLockSlim
中标记了SupportsRecursion
不会引发异常:
_lock.EnterReadLock(); _lock.EnterReadLock();
以上是关于使用嵌套异步调用锁定的主要内容,如果未能解决你的问题,请参考以下文章