【问题标题】:Is it Safe to use ReaderWriterLockSlim in an async method在异步方法中使用 ReaderWriterLockSlim 是否安全
【发布时间】:2023-04-08 14:08:01
【问题描述】:

由于ReaderWriterLockSlim 类使用线程 ID 来查看谁拥有锁,因此在不保证所有方法都将在同一个线程上执行的异步方法中使用它是否安全。

例如。

    System.Threading.ReaderWriterLockSlim readerwriterlock = new System.Threading.ReaderWriterLockSlim();
    private async Task Test()
    {
        readerwriterlock.EnterWriteLock();
        await Task.Yield(); //do work that could yield the task
        readerwriterlock.ExitWriteLock(); //potentailly exit the lock on a different thread
    }

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    在异步方法中使用 ReaderWriterLockSlim 是否安全

    是的,不是的。在异步方法中使用它可能是安全的,但在异步方法中使用它可能不安全,在这种方法中您进入和退出跨越 await 的锁。

    在这种情况下,不,这不一定是安全的。

    ExitWriteLock 必须从调用EnterWriteLock 的同一线程调用。否则,它会抛出一个SynchronizationLockException。从documentation 开始,在以下情况下会引发此异常:

    当前线程还没有进入写模式的锁。

    唯一安全的情况是,如果在异步方法中使用该方法,该方法总是在存在当前SynchronizationContext 的环境中,它将把事情移回同一个线程(即:Windows 窗体, WPF 等),并且未被嵌套异步调用使用,其中调用链上的“父级”设置了带有ConfigureAwait(false) 的任务(这将阻止Task 捕获同步上下文)。如果您处于该特定场景中,您会知道线程将被维护,因为 await 调用会将您编组回调用上下文。

    【讨论】:

    • 我正在阅读这个问题和两个答案,你和 Stephen Cleary 相互矛盾。我糊涂了。例如,我理解为什么在 WPF 中,锁不是问题,因为它是同一个线程首先获得了锁,但斯蒂芬说,尽管是同一个线程,但无论环境如何,ReaderWriterLockSlim 始终是异步的问题跨度>
    • @DonBox 好吧,这不是“总是”问题——它可以工作,但很危险。我也建议这样做。正如他所提到的,在相同的上下文中,您仍然会遇到重入问题,这将导致死锁 - 如果您知道您的例程永远不会被调用 >1 次重入,它应该可以工作,但这是一个很大的“如果”
    • 即使使用同步上下文,您也可能遇到无效递归问题,您的同步线程获得读锁,等待,然后在同步线程上运行的不同任务尝试获得写锁。这是ReaderWriterLockSlim 的无效递归并将抛出。
    【解决方案2】:

    没有。不应像在您的示例中那样使用线程仿射协调原语。

    您正确识别了在await 之后可以使用不同线程恢复的问题。由于async 方法提前返回的方式,还有另一个问题:调用者不知道锁已被持有。

    ReaderWriterLockSlim 默认情况下是一个非递归锁,所以如果另一个async 方法尝试获取相同的锁,你会得到一个死锁。即使你让锁递归,你仍然会遇到一个问题:在持有锁的时候不应该调用任意的最终用户代码,这就是你在使用await时所做的事情。

    SemaphoreSlim typeasync-aware(通过它的WaitAsync 方法),Stephen Toub 有一个series of async coordination primitives 也可以在我的AsyncEx library 中找到。

    【讨论】:

    • 您能否为第 3 段举一个具体的例子“所以如果另一个异步方法尝试获取相同的锁,您将遇到死锁”。我不明白死锁是如何出现在像 WPF 这样的环境中的。
    • @DonBox:只需单击一个按钮即可锁定作者,然后执行await Task.Delay(10000); 并在 10 秒前再次单击它。
    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 2011-08-13
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多