【问题标题】:Concurrent Dictionary safety usage [duplicate]并发字典安全使用[重复]
【发布时间】:2017-12-19 20:57:56
【问题描述】:

我需要以线程安全的方式来获取 ConcurrentDictionary(string, List) 的每一项

使用以下结构是否安全?

foreach (var item in concurrentDict)
{
     var readonlyCollection = item.Value.AsReadOnly();
     //use readonly collection, (I need only Values of the concurrent dictionary)
}

我想使用字典安全的值。

【问题讨论】:

  • 如果除了阅读什么都不做,会有什么危险呢?只有在读写时才会遇到线程问题。
  • 谢谢。我可以使用 foreach (var dictValue in concurrentDictionary.Values) { foreach(item in dictValue) { } } 吗?
  • 只需尝试并找出答案(是的,您可以)花费更少的时间

标签: c# concurrentdictionary


【解决方案1】:

foreach 部分很好,但需要注意的是并发添加的项目可能会或可能会包含在迭代中。不过,你不会得到例外。

但是,您需要小心item.Value,它的类型为List,因为列表不是线程安全的。如果您在循环中读取列表时另一个线程修改了列表,您可能会遇到异常。

在您的列表中调用AsReadOnly() 并没有帮助,因为您得到的是原始列表的包装。如果从包装器内的原始列表中读取会抛出异常,那么从包装器中读取也会抛出。此外,您不能简单地通过制作嵌套列表的浅表副本来解决此问题,因为在制作副本时可能会执行并发修改。

一种方法是在阅读和编写列表时lock

foreach (var item in concurrentDict) {
    List<string> listCopy;
    lock (item.Value) {
        listCopy = item.Value.ToList();
    }
     //use collection copy
}

当写入线程更改字典内的列表时,它需要执行相同的锁定:

if (concurrentDict.TryGetValue("mykey", var out list)) {
    lock (list) {
        list.Add("newValue");
    }
}

【讨论】:

  • 谢谢。但是,如果我在 foreach 中只得到字典的值,就不可能得到异常,对吗?是否需要将我的列表转换为正文中的 ReadOnlyCollection 或者我可以确定我的项目不会被更改。
  • @AndreyMisnikov 这取决于写作线程。如果他们每次都创建新列表,然后将其放入concurrentDict,并且不再触摸该列表的内容,那么您不需要复制,也不需要调用AsReadOnly。如果写入方在列表仍在concurrentDict 中时对其进行了修改,则需要进行复制和同步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 2021-08-03
相关资源
最近更新 更多