2

我正在循环填充ConcurrentDictionary一个:Parallel.ForEach

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是线程安全的。

4

3 回答 3

4

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

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

如问题评论中所述,这假设它ItemCollection是线程安全的。

于 2014-06-12T13:22:22.273 回答
1

您需要使用该GetOrAdd方法。

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

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

ItemCollection collection = result.GetOrAdd(someKey, _ => new ItemCollection());
collection.Add(newItem);
于 2014-06-12T13:23:29.527 回答
1

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

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

lock(collection)
    collection.Add(...);

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

var collection = result.GetOrAdd(someKey, k => new ItemCollection());
collection.Add(...);
于 2014-06-12T13:23:50.897 回答