When Iterating Over ConcurrentDictionary and only reading, is ConcurrentDictionary locked?
This is how ConcurrentDictionary.GetEnumerator
Is implemented:
/// <remarks>/// The enumerator returned from the dictionary is safe to use concurrently with/// reads and writes to the dictionary, however it does not represent a moment-in-time /// snapshot of the dictionary. The contents exposed through the enumerator may contain /// modifications made to the dictionary after <see cref="GetEnumerator"/> was called./// </remarks>public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator(){ Node[] buckets = m_tables.m_buckets; for (int i = 0; i < buckets.Length; i++) { // The Volatile.Read ensures that the load of the fields of 'current' // doesn't move before the load from buckets[i]. Node current = Volatile.Read<Node>(ref buckets[i]); while (current != null) { yield return new KeyValuePair<TKey, TValue>(current.m_key, current.m_value); current = current.m_next; } }}
As you see, the iteration is lock free, and simply yields a immutable struct (KeyValuePair
) which is returned to the caller for each iteration. That is why it cant guarantee a snapshot-in-time of the ConcurrentDictionary
This will definitely not have a performance effect on adding/updating new values while iterating, but it simply cant guarantee that your admin will see the most updated snapshot of the dictionary.
- You can browse the rest of the source code yourself viahttp://sourceof.net
- And you can also check out Inside the Concurrent Collections:ConcurrentDictionary by Simon Cooper.
- Are all of the new concurrent collections lock-free?
This is what documentation is saying:
The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called.
http://msdn.microsoft.com/en-us/library/dd287131(v=vs.110).aspx
So, if you want "snapshot" behavior, you will have to make a copy of the Keys collection and iterate over the copy, otherwise you will iterate over mutable thread safe collection.