Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ConcurrentDictionary has AddOrUpdate and GetOrAdd, but Dictionary has not?

In the .NET Framework, there is Dictionary and ConcurrentDictionary. These provide method like Add, Remove, and so on...

I know when we design a multi-thread program, we use ConcurrentDictionary to replace Dictionary for thread-safety.

I wonder why ConcurrentDictionary has AddOrUpdate, GetOrAdd and similar methods, while Dictionary has not.

We always like below code to get object from a Dictionary:

var dict = new Dictionary<string, object>();
object tmp;
if (dict.ContainsKey("key"))
{
       tmp = dict["key"];
}
else
{
       dict["key"] = new object();
       tmp = new object();
}

but when using ConcurrentDictionary, similar code is just one line only.

var conDict = new ConcurrentDictionary<string, object>();
var tmp = conDict.GetOrAdd("key", new object());

I expect .NET to have those methods, but why it doesn't?

like image 263
Po-Sen Huang Avatar asked Aug 23 '19 07:08

Po-Sen Huang


People also ask

What is the purpose of the ConcurrentDictionary TKey TValue class?

Represents a thread-safe collection of key/value pairs that can be accessed by multiple threads concurrently.

Is GetOrAdd thread-safe?

The GetOrAdd function The vast majority of methods it exposes are thread safe, with the notable exception of one of the GetOrAdd overloads: TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory); This overload takes a key value, and checks whether the key already exists in the database.

Is ConcurrentDictionary AddOrUpdate thread-safe?

It is thread safe in your usage. It becomes not thread safe when the delegate passed to AddOrUpdate has side effects, because those side effects may be executed twice for the same key and existing value.

How does ConcurrentDictionary work in C#?

ConcurrentDictionary is thread-safe collection class to store key/value pairs. It internally uses locking to provide you a thread-safe class. It provides different methods as compared to Dictionary class. We can use TryAdd, TryUpdate, TryRemove, and TryGetValue to do CRUD operations on ConcurrentDictionary.


1 Answers

Because such methods are:

  1. A bare minimum for working in a concurrent context. You can't split the Get and Add in two separate steps without locking, and still yield correct results.

  2. When implemented for Dictionary<TKey, TValue>, it implicitly indicates some level of thread-safety, as if Dictionary<TKey, TValue> can handle this in a correct matter. It can't, so it is just not implemented. That doesn't stop you for making an extension method to do something similar.

     public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> valueGenerator)
     {
         //
         // WARNING: this method is not thread-safe and not intended as such.
         //
         if (!dict.TryGetValue(key, out TValue value))
         {
             value = valueGenerator(key);
    
             dict.Add(key, value);
         }
    
         return value;
     }
    
like image 129
Patrick Hofman Avatar answered Oct 02 '22 12:10

Patrick Hofman