Updating fields of values in a ConcurrentDictionary

ConcurrentDictionary doesn't help you with accessing members of stored values concurrently, just with the elements themselves.

If multiple threads call TestIt, you should get a snapshot of the collection and lock the shared resources (which are the individual dictionary values):

foreach (KeyValuePair<int, Class1> kvp in dict.ToArray())
{
    Class1 value = kvp.Value;
    lock (value)
    {
        value.Counter = value.Counter + 1;
    }
}

However, if you want to update the counter for a specific key, ConcurrentDictionary can help you with atomically adding a new key value pair if the key does not exist:

Class1 value = dict.GetOrAdd(42, key => new Class1());
lock (value)
{
    value.Counter = value.Counter + 1;
}

AddOrUpdate and TryUpdate indeed are for cases in which you want to replace the value for a given key in a ConcurrentDictionary. But, as you said, you don't want to change the value, you want to change a property of the value.


You can use the AddOrUpdate function.

Here is how you can increment the current value by 1:

dict.AddOrUpdate(key, 1, (key, oldValue) => oldValue + 1);

First, to solve your locking problem:

class Class1
{
    // this must be a variable so that we can pass it by ref into Interlocked.Increment.
    private int counter;

    public int Counter
    {
        get{return counter; }
    }

    public void Increment()
    {
        // this is about as thread safe as you can get.
        // From MSDN: Increments a specified variable and stores the result, as an atomic operation.
        Interlocked.Increment(ref counter);

        // you can return the result of Increment if you want the new value,
        //but DO NOT set the counter to the result :[i.e. counter = Interlocked.Increment(ref counter);] This will break the atomicity.
    }
}

Iterating the just values should be faster than iterating the key value pair. [Though I think iterating a list of keys and doing the look-ups will be faster still on the ConcurrentDictionary in most situations.]

class Test
{
    private ConcurrentDictionary<int, Class1> dictionary = new ConcurrentDictionary<int, Class1>();

    public void TestIt()
    {
        foreach (var foo in dictionary.Values)
        {
            foo.Increment();
        }
    }

    public void TestItParallel()
    {
        Parallel.ForEach(dictionary.Values,x=>x.Increment() );
    }

}