在异步方法中使用ReaderWriterLockSlim安全吗?

本文关键字:安全 ReaderWriterLockSlim 异步方法 | 更新日期: 2023-09-27 18:08:08

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

在异步方法中使用ReaderWriterLockSlim安全吗?

在异步方法中使用ReaderWriterLockSlim安全吗

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

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

ExitWriteLock必须从调用EnterWriteLock的同一个线程中调用。否则,抛出一个SynchronizationLockException。从文档中可以看出,当:

当前线程未进入写模式。

唯一安全的时候是,如果这是在一个异步方法中使用的,这个方法总是在一个环境中,那里有一个当前的SynchronizationContext,它将把东西移回同一个线程(即:Windows窗体,WPF等),并且不是由一个嵌套的异步调用使用,其中一个"父"在调用链上设置了一个任务与ConfigureAwait(false)(这将防止Task捕获同步上下文)。如果您在那个特定的场景中,您将知道该线程将被维护,因为await调用将把您送回调用上下文。

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

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

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

SemaphoreSlim类型是async -aware(通过它的WaitAsync方法),Stephen Toub有一系列的async协调原语也可以在我的AsyncEx库。