我有一个Parallel.ForEach循环做一些处理。但是第一个操作是在未包含密钥的情况下在字典中添加值。添加它时出错,它表示密钥已经在字典中。我猜这个密钥是在这个线程的.Contains检查之后但是在添加之前由并行进程添加的。除了将该行放在try-catch中之外,还有另一个我可以用来防止该错误的简单解决方案吗?
Parallel.ForEach(branchFixes, b =>
{
Parallel.ForEach(b.Value, t =>
{
var team = t.Key;
if (!resultTeamDict.ContainsKey(team))
{
resultTeamDict.Add(team, new Dictionary<FixItem, Dictionary<BranchInfo, bool>>());
}
});
});
答案 0 :(得分:15)
即使在竞争条件之外,Dictionary<,>
也不是线程安全的。您应该使用ConcurrentDictionary<,>
,在这种情况下可能使用AddOrUpdate
方法以原子方式执行修改。 (我假设您要为“嵌套”字典添加值。否则,请考虑TryAdd
。)
答案 1 :(得分:4)
您可以在.NET 4.5中使用ConcurrentDictionary,并使用TryAdd替换ContainsKey和Add方法调用。见http://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
答案 2 :(得分:2)
这是&#34;使用时间检查时间的教科书示例&#34;错误:在检查字典是否包含密钥和Add
调用之间,另一个线程可能已经插入了该项,使Add
的前提条件无效。
解决方案是使用ConcurrentDictionary<T>
或相互排除的线程通过锁或其他同步工具同时更新字典。
您可能希望对代码进行概要分析,以检查触发线程是否值得 - 在这种情况下,开销可能非常高。