我相信这是有效的,我已经用多个并发线程测试了它(虽然没有详尽的竞争条件和死锁):
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
因为我正在进行两次“冒险”演习:
ConcurrentDictionary
删除值,同时枚举它(这似乎没问题)。Value
的{{1}}部分。必要的是因为操纵值的字段不是线程安全的,只是操纵ConcurrentDictionary
的值本身是线程安全的(上面的代码是一个更大的代码块的片段,其中值的字段实际上被操作)。 / LI>
醇>
答案 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