【问题标题】:Does this ReaderWriterLockSlim locking pattern look right?这个 ReaderWriterLockSlim 锁定模式看起来正确吗?
【发布时间】:2012-03-20 17:22:35
【问题描述】:

我一直在使用ReaderWriterLockSlim 来同步读/写,到目前为止效果很好。

我有一个对象集合,读/写锁保存在Dictionary<string, ReaderWriterLockSlim> 中。我有一个场景,我需要原子地获取多个读锁。我确定我没有任何代码允许一个线程同时尝试持有多个写锁,这让我认为下面的代码将毫无问题地工作。

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

假设以下情况,是否有人认为此代码有任何问题:

  1. 在其他地方,不允许持有写锁的线程持有任何其他锁(读或写)
  2. 多个线程可以同时持有任意数量的读锁

有什么想法吗?

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

【问题讨论】:

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

标签: c# thread-safety readerwriterlockslim


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是一个老问题,但我认为用最终解决方案更新它仍然会很好。尽管我从未遇到过上述问题,但我采用了与获得锁相反的顺序退出锁的谨慎做法。因此最终的代码看起来像这样:

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

    【讨论】:

      猜你喜欢
      • 2014-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      相关资源
      最近更新 更多