确保字典中有值的列表的线程安全操作

时间:2013-01-17 11:36:49

标签: c# multithreading thread-safety locking

我有一个Dictionary<object1, List<object2>(我为我的结构做了一个抽象化,这有点复杂了。)

字典中的列表在非并行上下文中初始化,但向列表中添加新元素需要线程安全方法。删除项目不会发生(字典对象将在事务结束时处理)。 此外,键值对仅在初始化时添加,因此在工作期间不会在字典中添加或删除键,只会更新值。

我无法使用concurent集合,我陷入了旧的.NET Framework。

起初我用ReadWriteSlimlock锁定了整个字典。嗯,这是非常糟糕的表现。有很多添加操作正在发生,他们只是等待另一个。仅锁定每个列表是一个更好的解决方案,因为至少我正在为每个键并行执行操作。 此外,添加操作不简单list.Add(object2),在添加时需要在线程安全区域中进行一些其他复杂操作。

但我不知道实施它的最佳方法是什么:

  1. lock(dictionary.Value)
  2. 使用ReadWriteSlimlock字典(每个密钥一个字符)?
  3. 还有其他更好的解决方案吗?

3 个答案:

答案 0 :(得分:2)

另一个解决方案可能是实现你的concurent List<object>类。 类似的东西:

public class ConcurentList {
    private object sync = new object(); 
    private List<object> realList = new List<object>(); 


    public void Add(object o) {
        lock(sync){
           realList.Add(o);
        }
    }   

    /** ADD OTHERE METHODS IMPEMENTATION IF NEED **/

}

并在字典中有:

Dictionary<object1, ConcurentList>

为什么封装而不是扩展List<object>,因为Add方法不是虚拟的,所以你可以“覆盖”它的唯一方法是使用{{1 }}}关键字,如果在完全相同的类型上使用,则保证仅被称为 ,这意味着如果将列表转换为基础,则不会调用它,所以洞建筑将失败。

通过封装,您只向调用者提供一个控制所有内容的方法。

不知道这个解决方案是否符合您的需求,但希望它能为您提供一些管理内容的提示。

答案 1 :(得分:1)

为什么不编写Dictionary<>List<>自己的并发线程安全变体?这就是我为.NET 2所做的。

我个人选择了ReaderWriterLockSlim,因为它允许你根据访问模式控制锁定,而且大多数情况下我的列表都是从写入的内容中读取的。

但是,您正在进行大量添加,因此您可能需要同时尝试(lockReaderWriterLockSlim)并查看哪些效果更好。

答案 2 :(得分:1)

如果从列表中读取与写入同时发生,则为每个字典条目构造ReaderWriterLockSlim对象将是最佳解决方案,因为多个读取器将能够在同一列表上同时进行。它只比使用lock(key)稍微困难一点,并且在比其他列表更频繁地读取少量列表的情况下,它有可能提高性能。

如果你走ReaderWriterLockSlim路线,最好将列表和锁包装在一个类中,而不是仅为读写器锁创建一个单独的字典:

class LockableList {
    public ReaderWriterLockSlim RwLock {get;private set;}
    public List<object2> Data {get;private set;}
    public LockableList() {
        RwLock = new ReaderWriterLockSlim();
        Data = new List<object2>();
    }
}
...
Dictionary<object1,LockableList> myDictionary;

组合列表和外观可让您查找字典条目一次,将其锁定以供阅读或适当写入,并使用相关列表进行工作。