C#.NET 4.0 ConcurrentDictionary:一个锁中的TryRemove?

时间:2010-06-21 11:22:02

标签: c# multithreading .net-4.0 locking

我相信这是有效的,我已经用多个并发线程测试了它(虽然没有详尽的竞争条件和死锁):

public static System.Collections.Concurrent.ConcurrentDictionary<string, item> dict =
        new System.Collections.Concurrent.ConcurrentDictionary<string, item>();
public static item dump;

...

foreach (System.Collections.Generic.KeyValuePair<string, item> x in dict)
{
    lock (x.Value)
    {
        if (x.Value.IsCompleted)
        {
            dict.TryRemove(x.Key, out dump);
        }
    }
}

这个问题是这个问题的延续:

Can I remove items from a ConcurrentDictionary from within an enumeration loop of that dictionary?

这个问题:

Updating fields of values in a ConcurrentDictionary

因为我正在进行两次“冒险”演习:

  1. ConcurrentDictionary删除值,同时枚举它(这似乎没问题)。
  2. 锁定Value的{​​{1}}部分。必要的是因为操纵值的字段不是线程安全的,只是操纵ConcurrentDictionary的值本身是线程安全的(上面的代码是一个更大的代码块的片段,其中值的字段实际上被操作)。 / LI>

2 个答案:

答案 0 :(得分:4)

在迭代它时从并发字典中删除值很好。它可能有一些性能影响(我不确定),但它应该有用。

请注意,您没有锁定ConcurrentDictionary内部的内容 - 您正在锁定与item对象关联的监视器。我个人不希望这样做:要么这些项目应该是线程安全的(无论如何都可以操纵它们)或者(最好是)不可变的,这样你就可以从任何线程中观察它们而不需要锁定。或者,您可以将单个属性设置为您正在检查线程安全的,当然。记录你做的任何事情!

最后,您对out dump的使用似乎有点可疑。重点是要给TryRemove一些东西吗?如果是这样,我会使用局部变量而不是静态变量。

答案 1 :(得分:0)

我最近发现的一个很好的选择是删除只是键/值匹配,这意味着你可以保证删除一个没有变化的对象(最好是值类型,而不是引用类型) 。例如:

 ConcurrentDictionary<string, int> cc = new ConcurrentDictionary<string, int>();

        cc.GetOrAdd("1", 1);

现在假设以下两行是在并发/多线程场景中运行的。

        cc.AddOrUpdate("1", 2, (a,b) => b + 1);

         var removeSuccess = ((ICollection<KeyValuePair<string, int>>)cc).Remove(
    new KeyValuePair<string, int>("1", 1));

如果值没有改变,你将成功删除“1”,否则会失败,因为你已经有了同一个键的新值。

有关详细信息,请查看以下内容: http://thargy.com/2012/09/the-hidden-secret-of-the-concurrent-dictionary/http://blogs.msdn.com/b/pfxteam/archive/2011/04/02/10149222.aspx