12

The MSDN documentation of System.Collections.Concurrent.ConcurrentDictionary says:

Thread Safety

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

(emphasis mine)

This seems self-contradictory. "All members are thread-safe. But members [sometimes] are not thread-safe."

I do understand that extension methods are of course not guaranteed to be thread safe.

But what do they mean by "accessed through one of the interfaces"? Is TryGetValue (a member of the IDictionary<TKey, TValue> interface) thread-safe?

Peter
  • 3,322
  • 3
  • 27
  • 41

3 Answers3

6

Notice the section of the documentation that covers explicit interface implementations. E.g. the class implements IDictionary.Add. This method is not a public or protected member of the class, but may be accessed via the IDictionary interface. It is these such members that are not being guaranteed to be thread safe.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • 1
    Any idea why that is the case? – Peter Jul 12 '16 at 08:19
  • 4
    @Peter - well, for one, there's little value in *providing* such a guarantee since if you're accessing it via such an interface, it's unlikely that the calling code can make use of the guarantee (since other implementations won't offer such guarantees). – Damien_The_Unbeliever Jul 12 '16 at 08:24
4

Due to Explicit vs Implicit interface implementation.

If you take a look at the source code for ConcurrentDictionary<TKey, TValue> you may see that there are some methods that explicitly implement an interface (like object IDictionary.this[object key]) which although internally call the thread-safe version of the same operation this behavior may change in the future.

Think of it as division of responsibility: If I (as a class) receive an instance of ConcurrentDictionary<TKey, TValue> I know that it's that instance's responsibility to perform operations in a thread-safe manner.

However, if I (again as a class) receive an instance of IDictionary<TKey, TValue> then I should be aware if there should or shouldn't be a thread-safety concern. If there is no such concern I just use the dictionary as it is but if thread-safety is required it's my responsibility to perform all operations in a thread-safe manner.

Community
  • 1
  • 1
RePierre
  • 9,358
  • 2
  • 20
  • 37
3

There is a specific section in the documentation that makes clear not everything is thread-safe in the ConcurrentDictionary<TKey, TValue>:

All these operations are atomic and are thread-safe with regards to all other operations on the ConcurrentDictionary<TKey, TValue> class. The only exceptions are the methods that accept a delegate, that is, AddOrUpdate and GetOrAdd. For modifications and write operations to the dictionary, ConcurrentDictionary<TKey, TValue> uses fine-grained locking to ensure thread safety. (Read operations on the dictionary are performed in a lock-free manner.) However, delegates for these methods are called outside the locks to avoid the problems that can arise from executing unknown code under a lock. Therefore, the code executed by these delegates is not subject to the atomicity of the operation.

So there are some general exclusions and some situations specific to ConcurrentDictionary<TKey, TValue>:

  • The delegates on AddOrUpdate and GetOrAdd are not called in a thread-safe matter.
  • Methods or properties called on an explicit interface implementation are not guaranteed to be thread-safe;
  • Extension methods called on the class are not guaranteed to be thread-safe;
  • All other operations on public members of the class are thread-safe.
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 2
    That's not the "usual" standard quote - the usual one only references static members. Here, more guarantees are being offered about instance members. (I do believe this quote is quite common in `System.Collections.Concurrent` however) – Damien_The_Unbeliever Jul 12 '16 at 08:04
  • Okay. Didn't even notice that. @Damien_The_Unbeliever. Will remove the first part since it isn't really adding much too. – Patrick Hofman Jul 12 '16 at 08:05
  • The "all these operations"-section is below a table of few additional methods provided by ConcurrentDictionary, and only seems to refer to those, no? – Peter Jul 12 '16 at 08:08
  • Indeed, but the other section you reference states: "All public and protected members". – Patrick Hofman Jul 12 '16 at 08:09