2010-07-22 93 views
3

我有一个映射,每个键可以有多个关联的值。我认为ConcurrentDictionary可能会帮助我更容易地编写该映射以用于多线程环境,但这些方法似乎是围绕单个值构建的。我发现AddOrUpdate()让我修改该值,如果它已经存在,但它不能保证该操作的原子性,所以它看起来毫无意义?有没有人有解决这种情况的好策略?您可以使用ConcurrentDictionary进行一对多映射吗?

对不起,我想我有点含糊。我想为一个键有多个值,即有一个IList与键相关联。但我希望能够以安全的方式添加/删除多值中的值。它看起来像AddOrUpdate +委托方法可能会导致事情迷路,如果在同一时间对它进行多次调用?

+0

你已经在标签中有C#了。你也不需要把它放在标题中。此外,你的问题与C#4.0无关。 – 2010-07-22 18:57:05

回答

1

我认为AddOrUpdate是原子的,但它看起来对代表来说不是原子的。抱歉!

,这可能有助于参考:http://blogs.msdn.com/b/pfxteam/archive/2009/11/06/9918363.aspx

+0

你错了。该文档指出,由于用户代码的不可预测性,对代理的调用不在锁定下进行。 – evilfred 2010-07-22 18:04:53

+0

从您的链接:“关于集合上其他变异方法的原子(例如TryAdd/TryUpdate/TryRemove /等),不包括用户提供的委托的执行。” – evilfred 2010-07-22 18:05:44

+0

好吧,我明白你的意思了。我剔除了它并被曲解了。编辑帖子反映。 – mquander 2010-07-22 18:52:55

0

看起来既AddOrUpdateTryUpdate会工作。

编辑

我可能也错了。如果是这样,我认为文档没有足够清晰的说,所以我们来看看代码。反射器的礼貌:

public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue local; 
    TValue local3; 
    if (key == null) 
    { 
     throw new ArgumentNullException("key"); 
    } 
    if (addValueFactory == null) 
    { 
     throw new ArgumentNullException("addValueFactory"); 
    } 
    if (updateValueFactory == null) 
    { 
     throw new ArgumentNullException("updateValueFactory"); 
    } 
    do 
    { 
     if (!this.TryGetValue(key, out local3)) 
     { 
      TValue local2; 
      local = addValueFactory(key); 
      if (!this.TryAddInternal(key, local, false, true, out local2)) 
      { 
       continue; 
      } 
      return local2; 
     } 
     local = updateValueFactory(key, local3); 
    } 
    while (!this.TryUpdate(key, local, local3)); 
    return local; 
} 

现在,如果更新了工厂现有列表,并返回一个额外成员一个新的,它确实看我,好像这将是原子。如果出现竞争状况,失败者将再次更新工厂。我错了吗?

+0

为什么TryAddInternal会返回与我们放入的东西不同的东西? – evilfred 2010-09-29 22:18:20

+0

最有可能TryAddInternal返回键的实际值,无论它是否返回false(即 - 无论是否添加第二个参数)。 – 2010-09-29 22:33:03

+1

如果我们不知道TryAddInternal是什么,那么阅读该代码就像阅读茶叶一样。 – evilfred 2010-09-30 00:05:10