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 via http://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?