5

I have to remove items from ConcurrentDictionary by some keys. Like this:

ConcurrentDictionary<SomeClass, string> dict = new ConcurrentDictionary<SomeClass, string>();
//adding some values
var keys = dict.Keys.Where(k => k.Name == "Example");
foreach (var key in keys)
    dict.TryRemove(key, out _);

The question is: I am enumerating the keys collection when is start looping. What if somebody will change the dict at the same time? Does dict.Keys returns a snapshot?

Nikolay
  • 171
  • 1
  • 17
  • 1
    It returns a copy. See [here](https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/collections/Concurrent/ConcurrentDictionary.cs#L1931-L1955). – ProgrammingLlama Dec 28 '17 at 06:13
  • 1
    It returns a `snapshot` (so yes it will work fine). I would suggest using `var keys = dict.Select(z => z.Key).Where(k => k.Name == "Example");` to reduce the need for snapshot (i.e. locking) - i.e. it will generally be faster. Or just `foreach` over the dictionary like in the duplicate. – mjwills Dec 28 '17 at 07:17

2 Answers2

5

Look at source code:

public ICollection<TKey> Keys
{
    get { return GetKeys(); }
}

private ReadOnlyCollection<TKey> GetKeys()
{
    int locksAcquired = 0;
    try
    {
        AcquireAllLocks(ref locksAcquired);

        int count = GetCountInternal();
        if (count < 0) throw new OutOfMemoryException();

        List<TKey> keys = new List<TKey>(count);
        for (int i = 0; i < _tables._buckets.Length; i++)
        {
            Node current = _tables._buckets[i];
            while (current != null)
            {
                keys.Add(current._key);
                current = current._next;
            }
        }

        return new ReadOnlyCollection<TKey>(keys);
    }
    finally
    {
        ReleaseLocks(0, locksAcquired);
    }
}

It locks collection and returns copy of keys

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Backs
  • 24,430
  • 5
  • 58
  • 85
4

All public and protected members of ConcurrentDictionary are thread-safe and may be used concurrently from multiple threads. However, members accessed through one of the interfaces the ConcurrentDictionary implements, including extension methods, are not guaranteed to be thread safe and may need to be synchronized by the caller.

from https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx#Anchor_10

programtreasures
  • 4,250
  • 1
  • 10
  • 29