Habib's answer is excellent, but for multi-threaded environments if you use a HashSet<T>
then by consequence you have to use lock
s to protect access to it. I find myself more prone to creating deadlocks with lock
statements. Also, lock
s yield a worse speedup per Amdahl's law because adding a lock
statement reduces the percentage of your code that is actually parallel.
For those reasons, a ConcurrentDictionary<T,object>
fits the bill in multi-threaded environments. If you end up using one, then wrap it like you did in your question. Just new
up object
s to toss in as values as needed, since the values won't be important. You can verify that there are no lock
statements in its source code.
If you didn't need mutability of the collection then this would be moot. But your question implies that you do need it, since you have an AddEntity
method.
Additional info 2017-05-19 - actually, ConcurrentDictionary
does use locks internally, although not lock
statements per se--it uses Monitor.Enter
(check out the TryAddInternal
method). However, it seems to lock on individual buckets within the dictionary, which means there will be less contention than putting the entire thing in a lock
statement.
So all in all, ConcurrentDictionary
is often better for multithreaded environments.
It's actually quite difficult (impossible?) to make a concurrent hash set using only the Interlocked methods. I tried on my own and kept running into the problem of needing to alter two things at the same time--something that only locking can do in general. One workaround I found was to use singly-linked lists for the hash buckets and intentionally create cycles in a list when one thread needed to operate on a node without interference from other threads; this would cause other threads to get caught spinning around in the same spot until that thread was done with its node and undid the cycle. Sure, it technically didn't use locks, but it did not scale well.