使用嵌套异步调用锁定

问题描述 投票:12回答:3

我正在研究多线程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();
     }

}
c# windows-phone-8 async-await semaphore
3个回答
12
投票

递归锁是really bad idea(IMO;链接是我自己的博客)。对于async代码,这是尤其是 true。要使async兼容的递归锁起作用是很困难的。我有一个proof-of-concept here,但有一个合理的警告:我确实建议在生产中使用此代码,[此代码将not卷入AsyncEx,并且已进行not全面测试。

您应该做的是按照@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 }


7
投票
这是我在这种情况下的工作(仍然,我对任务没有经验,所以不要打败我;-)因此,基本上,您已经将实际实现移至非锁定方法,并在所有获取锁定的方法中使用它们。

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 } }


0
投票
您可以使用具有支持递归标志的System.Threading.ReaderWriterLockSlimdoc):

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();

© www.soinside.com 2019 - 2024. All rights reserved.