Is it allowed to remove items from a ConcurrentDictionary while iterating it in a Foreach loop?

135 Views Asked by At

I'm building an app in C# using Visual Studio. I'm using a ConcurrentDictionary. I'm iterating through all the elements in that ConcurrentDictionary, and perform an action on each element. If the action fails, I remove the element from the ConcurrentDictionary.

I know that this is bad behavior if you do that with normal Dictionaries, Lists, etc... But is it allowed with a ConcurrentDictionary?

So my question is: Is the below code fragment correct? More specifically, am I allowed to use TryRemove on the ConcurrentDictionary that I'm iterating?

foreach (var prop in _PropertyByPropId)
{
    // Add the Property to the Pool. If successfully parsed, we will get a SimId not equal to -1.
    int iSimId = PropertyPool.AddPropertyInPool(PNPDeviceID, prop.Value, PortName);
    if (iSimId != -1)
    {
        // If successful, also add it to the dictionary by iSimId
        if (!_PropertyBySimId.TryAdd(iSimId, prop.Value))
            // In the (very unlikely) case that a Property is added twice (same iSimId), we remove the second Property
            _PropertyByPropId.TryRemove(prop.Key, out _);
    }
    else
        // If unsuccessful, remove the Property
        _PropertyByPropId.TryRemove(prop.Key, out _);
}

I found an older thread removing-items-from-a-concurrentdictionary on this forum, but that seems to give answers related to the multithreading aspects of a ConcurrentDictionary. I think my question is different?

1

There are 1 best solutions below

2
On

Yes, it is perfectly valid to remove items from a ConcurrentDictionary<K,V> during an enumeration. All operations on this collections are thread-safe and atomic. Nevertheless, performing two atomic operations in succession does not equal to performing one combined atomic operation. It is entirely possible that the data in the ConcurrentDictionary<K,V> might become semantically corrupted, because two concurrent combined operations interfered with each other in an unexpected way. I am not in a position to judge if your specific scenario and usage, allows semantic data corruption to occur.

The ConcurrentDictionary<K,V> collection is excellent for simple multithreading scenarios, but becomes exponentially unsuitable, a headache and a bug factory, when the scenarios become more complicated. At some point of complexity it becomes more safe and productive to go with a standard Dictionary<K,V> protected with the lock statement, instead of trying to tame the concurrent beast.