Have a question regarding thread safety with ConcurrentDictionary
. From the API, I see that the enumerator is thread-safe, but I don't see the same for keys and values properties. My question is:
Is it safe to loop over the Keys
or Values
collection when there are other threads modifying it concurrently?
All public and protected members of ConcurrentDictionary are thread-safe and may be used concurrently from multiple threads. Since the . Values property is an implementation dictated by the IColletion interface it is public and therefore thread safe.
ConcurrentDictionary is thread-safe collection class to store key/value pairs. It internally uses locking to provide you a thread-safe class. It provides different methods as compared to Dictionary class. We can use TryAdd, TryUpdate, TryRemove, and TryGetValue to do CRUD operations on ConcurrentDictionary.
Represents a thread-safe collection of key/value pairs that can be accessed by multiple threads concurrently.
Concurrent. ConcurrentDictionary<TKey,TValue>. This collection class is a thread-safe implementation.
While I do like the documentation, I tend to verify things with a small program when in doubt or I feel that I might be assuming too much.
The following code verifies that indeed you can enumerate the values collection safely while adding or removing keys from a separate thread to that on which the enumeration is taking place. This will not cause the usual collection was modified exceptions. In more detail, here are a couple of test cases
Case 1: Enumerating Values and deleting a key
If you follow the following sequence:
The observed behavior is that the removed key will indeed be enumerated since it existed in the values collection when we started the enumeration. No exception will be raised.
Case 2: Enumerating Values and adding a key
The observed behavior is that the added key will not be enumerated since it did not exist in values collection when we started to enumerate it. No exception will be raised whether we use TryAdd or add by assigning directly to the dictionary ie dictionary[key] = value.
Sample Code
Here is the sample program that demonstrates both cases:
ConcurrentDictionary<int, int> dictionary = new ConcurrentDictionary<int, int>(); // Seed the dictionary with some arbitrary values; for (int i = 0; i < 30; i++) { dictionary.TryAdd(i, i); } // Reader thread - Enumerate the Values collection Task.Factory.StartNew( () => { foreach (var item in dictionary.Values) { Console.WriteLine("Item {0}: count: {1}", item, dictionary.Count); Thread.Sleep(20); } } ); // writer thread - Modify dictionary by adding new items and removing existing ones from the end Task.Factory.StartNew( () => { for (int i = 29; i >= 0; i--) { Thread.Sleep(10); //Remove an existing entry int removedValue; if (dictionary.TryRemove(i, out removedValue)) Console.WriteLine("Removed item {0}", removedValue); else Console.WriteLine("Did not remove item {0}", i); int iVal = 50 + i*2; dictionary[iVal] = iVal; Thread.Sleep(10); iVal++; dictionary.TryAdd(iVal, iVal); } } ); Console.ReadKey();
And here is the output in release mode:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With