Question

I have a Parallel.ForEach loop doing some treatment. But the first operation is to add a value in the dictionary if the key is not contained. I get an error when adding it, it says that the key is already in the dictionary. I guess that the key was added by a parallel process after the .Contains check of this thread, but before the add. Other than placing that line in a try-catch, is there another simple solution I can use to prevent that error?

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>>());
    }
  });
});
Était-ce utile?

La solution

Even aside from your race condition, Dictionary<,> isn't thread-safe. You should be using ConcurrentDictionary<,> and in this case probably the AddOrUpdate method to perform the modification atomically. (I assume that you want to add a value to the "nested" dictionary too. Otherwise, consider TryAdd.)

Autres conseils

You can use the ConcurrentDictionary in .NET 4.5 and replace the ContainsKey and Add method calls with TryAdd. See http://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

This is a textbook example of a "Time of Check to Time of Use" error: in between the check for whether the dictionary contains the key and the Add call, another thread might have inserted the item already, invalidating the preconditions of Add.

The solution is to use a ConcurrentDictionary<T> or mutually exclude threads from updating the dictionary at the same time via a lock or other synchronization tool.

You might want to profile your code to check whether firing off threads is even worth it--the overhead might be very high in this case.

I see some suggestions for ConcurrentDictionary. Just be carefull about optimization and performance issues. There's a difference between Dictionary and ConcurrentDictionary RunTime Complexity on inserting and reading data (it may go to 10 times slower with ConcurrentDictionary)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top