ConcurrentDictionary.GetOrAdd nested collections

70 Views Asked by At

I've read this question, but I still don't understand how GetOrAdd works if I have a nested collection.

Is ConcurrentDictionary.GetOrAdd truly thread-safe?

If I haven't created a nested collection yet, and GetOrAdd is called simultaneously from multiple threads, what happens? I expect the behavior that only one of the threads will be able to create a new collection, and the rest will receive the one already created and add a value there. Is this how it's going to happen?

var completions = subscribers.GetOrAdd(key, _ => new ConcurrentBag<TaskCompletionSource<string>>());
completions.Add(completion);
1

There are 1 best solutions below

0
Theodor Zoulias On BEST ANSWER

I expect the behavior that only one of the threads will be able to create a new collection,

Not exactly. It is entirely possible that more than one threads will create a new TValue, but only one of these TValues will be added in the dictionary. The other TValues will fall out of scope and will be discarded (garbage-collected).

and the rest will receive the one already created and add a value there.

Yes, all threads will interact with the same TValue. The GetOrAdd returns the TValue created by the thread that won the optimistic locking race. The race is optimistic because the valueFactory delegate is called outside the locks used internally by the ConcurrentDictionary<TKey,TValue> collection. This collection doesn't allow pessimistic locking, i.e. you can't use its internal locks for protecting your own code. Pessimistic locking could be beneficial in some scenarios, but this feature is simply not supported by this collection.