36

I'm using a dictionary inside of some Task.

Logically I have set it up so that my Keys will never clash, though sometimes when I am adding to the dictionary I get this Exception.

Index was outside the bounds of the array.
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at Rpc.<MapIntoRpc>b__4[T](Object x) in Rpc.cs:line 113
   at System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

I understand there can be concurrency issues from trying to remove or add the same Key multiple times, but I have accounted for that algorithmically.

What causes the add to sometimes fail? What is the best way to work around that?

Austin Harris
  • 1,676
  • 1
  • 17
  • 22
  • 1
    Can you post the code that is causing the exception? – Brad M Feb 26 '13 at 17:50
  • 1
    Are you adding to it from multiple threads? Likely a synchronization issue. – NominSim Feb 26 '13 at 17:50
  • 2
    Consider to use [`ConcurrentDictionary`](http://msdn.microsoft.com/en-us/library/dd287191.aspx) instead of trying to write corresponding thread-safe (lock-free?) code yourself... – Alexei Levenkov Feb 26 '13 at 17:52
  • I cant post the code that is causing the exception, but I am adding from multiple threads (tasks) and removing from multiple threads (tasks). – Austin Harris Feb 26 '13 at 17:56
  • 1
    "I understand there can be concurrency issues from trying to remove or add the same Key multiple times". I think there are concurrency issues for modifications (regardless of whether the keys are different). I think only reads are thread-safe for the standard containers. – Matt Smith Feb 26 '13 at 17:58
  • Ahh, any modification to the collection causes issues.. Got it. – Austin Harris Feb 26 '13 at 18:00

3 Answers3

58

You should have looked to the documentation. That what it says:

A Dictionary can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. For a thread-safe alternative, see ConcurrentDictionary.

Dzienny
  • 3,295
  • 1
  • 20
  • 30
24

Your issue is most likely synchronization. When a Dictionary is added to it sometimes needs to increase the size of the underlying structure (an array). If you are adding from multiple threads that may result in an IndexOutOfRangeException. You need to use locks etc. to make sure you are adding in a safe way.

Alternatively you can use a ConcurrentDictionary which is a thread-safe collection.

NominSim
  • 8,447
  • 3
  • 28
  • 38
18

So you might think Whatever! it will just break the one time - but nope:

Important: Once the dictionary is broken it is broken!

There goes three hours of sales (until IIS recycled on a schedule) because of a dictionary added for debugging purposes that wasn't ever even being read from.

enter image description here

Note: This was running for 3.5 years before I hit this condition.

 private Dictionary<string, string> _debugLookup;

 _debugLookup[key] = virtualPath;

This wasn't even a static dictionary - it was an MVC IViewLocationCache that was an instance method.

Community
  • 1
  • 1
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • 2
    Exact same thing happened to me. Sharing an `HttpClient` object in a multithreaded environment. If you need to add/remove headers (which is just a `Dictionary`)... it gets in to the state you posted above. I thought `HttpClient` was thread-safe! yeah, no. – Andy Feb 10 '18 at 05:43
  • facing the same problem but with a dictionary I can't change, I'm implementing an interface and returning the class with the dictionary. https://stackoverflow.com/questions/60105094/getting-indexoutofrangeexception-in-modelclientvalidationrule – Seichi Feb 07 '20 at 00:06