C# 这种ReaderWriterLockSlim锁定模式看起来合适吗?

C# 这种ReaderWriterLockSlim锁定模式看起来合适吗?,c#,thread-safety,readerwriterlockslim,C#,Thread Safety,Readerwriterlockslim,我一直使用它来同步读/写,到目前为止,它工作得相当好 我有一个对象集合,读/写锁保存在字典中。我有一个场景,需要以原子方式获取多个读锁。我确信我没有任何代码允许一个线程尝试同时持有多个写锁,这使我认为下面的代码可以正常工作 如果我用写锁而不是读锁来尝试下面的方法,我几乎可以肯定我会以死锁告终,除非我能确保锁总是以相同的顺序发生(在我的情况下我不能) 是否有人认为此代码存在以下问题: 在其他地方,不允许持有写锁的线程持有任何其他锁(读或写) 多个线程可以同时持有任意数量的读锁 有什么想法吗 pub

我一直使用它来同步读/写,到目前为止,它工作得相当好

我有一个对象集合,读/写锁保存在
字典中。我有一个场景,需要以原子方式获取多个读锁。我确信我没有任何代码允许一个线程尝试同时持有多个写锁,这使我认为下面的代码可以正常工作

如果我用写锁而不是读锁来尝试下面的方法,我几乎可以肯定我会以死锁告终,除非我能确保锁总是以相同的顺序发生(在我的情况下我不能)

是否有人认为此代码存在以下问题:

  • 在其他地方,不允许持有写锁的线程持有任何其他锁(读或写)
  • 多个线程可以同时持有任意数量的读锁
  • 有什么想法吗

    public void WithReaderLocksForItemsNamed(string[] itemNames, Action action)
        {
            // this gets locks for the items specified from my internation dictionary
            ReaderWriterLockSlim[ ] locks = LocksForItemsNamed( itemNames ) ;
    
            try
            {
                foreach( var @lock in locks )
                {
                    @lock.EnterReadLock( ) ;
                }
    
                action( ) ;
            }
            finally
            {
                foreach( var @lock in locks )
                {
                    if (@lock.IsReadLockHeld)
                    {
                        @lock.ExitReadLock( ) ;
                    }
                }
            }
        }
    

    它看起来还可以,但您可能需要对方法本身设置一个重入锁,当然,您需要在其中迭代源列表以获取锁。

    它看起来还可以,但您可能需要对方法本身设置重入锁,当然,一个迭代源代码列表以获得锁的问题。

    这是一个老问题,但我认为用最终的解决方案更新它还是不错的。虽然我从来没有遇到过上述问题,但我采用了谨慎的做法,按照与获得锁相反的顺序退出锁。因此,最终代码如下所示:

    public void WithReaderLocksForItemsNamed(string[] itemNames, Action action)
    {
        // this gets locks for the items specified from my internation dictionary
        ReaderWriterLockSlim[ ] locks = LocksForItemsNamed( itemNames ) ;
    
        try
        {
            foreach( var @lock in locks )
            {
                @lock.EnterReadLock( ) ;
            }
    
            action( ) ;
        }
        finally
        {
            foreach( var @lock in locks.Reverse() )
            {
                if (@lock.IsReadLockHeld)
                {
                    @lock.ExitReadLock( ) ;
                }
            }
        }
    }
    

    这是一个老问题,但我认为用最终的解决方案来更新它还是不错的。虽然我从来没有遇到过上述问题,但我采用了谨慎的做法,按照与获得锁相反的顺序退出锁。因此,最终代码如下所示:

    public void WithReaderLocksForItemsNamed(string[] itemNames, Action action)
    {
        // this gets locks for the items specified from my internation dictionary
        ReaderWriterLockSlim[ ] locks = LocksForItemsNamed( itemNames ) ;
    
        try
        {
            foreach( var @lock in locks )
            {
                @lock.EnterReadLock( ) ;
            }
    
            action( ) ;
        }
        finally
        {
            foreach( var @lock in locks.Reverse() )
            {
                if (@lock.IsReadLockHeld)
                {
                    @lock.ExitReadLock( ) ;
                }
            }
        }
    }
    

    您能解释一下为什么对同一个操作使用多个锁吗?该操作依赖于所有项在执行时保持不变。SQL世界中的一个例子是创建一个连接两个表的视图,我需要确保操作不会失败,因为在创建视图的过程中,引用的一个表正在被更改。这完全没关系,如果表在事件发生后立即更改……使用多个锁总是会带来死锁的好机会。这就是ReaderWriterLockSlim存在的原因——解决同时使用两个锁来保护资源的问题。你用锁保护什么样的资源?你的程序是多线程的吗?那么你的代码到底有什么问题?您是否遇到死锁?@Scott,该功能在概念上类似于我提到的SQL视图示例。需要在确保操作所依赖的资源保持不变(因此读取锁)的情况下执行操作。该程序本身并不是大规模多线程的,但有一些事件(从外部触发)可能会导致资源被删除和重新创建。我想确保我的操作在这些更新期间不会失败。请解释为什么对同一操作使用多个锁?该操作依赖于所有项在执行时保持不变。SQL世界中的一个例子是创建一个连接两个表的视图,我需要确保操作不会失败,因为在创建视图的过程中,引用的一个表正在被更改。这完全没关系,如果表在事件发生后立即更改……使用多个锁总是会带来死锁的好机会。这就是ReaderWriterLockSlim存在的原因——解决同时使用两个锁来保护资源的问题。你用锁保护什么样的资源?你的程序是多线程的吗?那么你的代码到底有什么问题?您是否遇到死锁?@Scott,该功能在概念上类似于我提到的SQL视图示例。需要在确保操作所依赖的资源保持不变(因此读取锁)的情况下执行操作。该程序本身并不是大规模多线程的,但有一些事件(从外部触发)可能会导致资源被删除和重新创建。我想确保我的操作在这些更新期间不会失败。