【问题标题】:Thread-safe changes to a ConcurrentDictionary对 ConcurrentDictionary 的线程安全更改
【发布时间】:2014-06-12 13:17:00
【问题描述】:

我在Parallel.ForEach 循环中填充ConcurrentDictionary

var result = new ConcurrentDictionary<int, ItemCollection>();

Parallel.ForEach(allRoutes, route => 
{
    // Some heavy operations

    lock(result)
    {
        if (!result.ContainsKey(someKey))
        {
            result[someKey] = new ItemCollection();
        }

        result[someKey].Add(newItem);
    }
}

如何在不使用 lock 语句的情况下以线程安全的方式执行最后一步?

编辑:假设ItemCollection 是线程安全的。

【问题讨论】:

  • ItemCollection.Add 线程安全吗?如果没有,你需要一把锁。
  • @ken2k:除了我的情况有条件因素。如果该键不存在,则创建一个新的ItemCollection,否则在该键的现有ItemCollection 中添加一个项目。
  • @dcastro:是的,请假设 ItemCollection 是线程安全的。

标签: c# parallel-processing task-parallel-library parallel.foreach concurrentdictionary


【解决方案1】:

我认为您想要GetOrAdd,它明确设计用于获取现有项目,或者如果给定键没有条目,则添加新项目。

var collection = result.GetOrAdd(someKey, _ => new ItemCollection());
collection.Add(newItem);

如问题 cmets 中所述,这假定 ItemCollection 是线程安全的。

【讨论】:

  • 这可能不像看起来那么安全:stackoverflow.com/questions/10486579/…
  • @jeffdot:在这种情况下,我认为这不是问题 - ItemCollection 构造函数不需要在任何锁中调用...您设想什么问题?
  • 因为讨论了锁定,并且因为 ConcurrentDictionary 确实有一个内部锁,我觉得我们增加了风险,让人们认为 GetOrAddAddOrUpdate 是原子的或被称为在字典的锁内。我已经注意到你给出了公平的警告,ItemCollection 必须是线程安全的。
【解决方案2】:

您需要使用GetOrAdd 方法。

var result = new ConcurrentDictionary<int, ItemCollection>();

int someKey = ...;
var newItem = ...;

ItemCollection collection = result.GetOrAdd(someKey, _ => new ItemCollection());
collection.Add(newItem);

【讨论】:

    【解决方案3】:

    假设ItemCollection.Add 不是线程安全的,您需要一个锁,但您可以减小临界区的大小。

    var collection = result.GetOrAdd(someKey, k => new ItemCollection());
    
    lock(collection)
        collection.Add(...);
    

    更新:由于它似乎是线程安全的,所以你根本不需要锁

    var collection = result.GetOrAdd(someKey, k => new ItemCollection());
    collection.Add(...);
    

    【讨论】:

    • OP 回复您的评论说 ItemCollection 线程安全的。
    • @JonSkeet 谢谢,没注意到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多