What's the Best Way of Implementing a Thread-Safe Dictionary

What's the best way of implementing a thread-safe Dictionary?

As Peter said, you can encapsulate all of the thread safety inside the class. You will need to be careful with any events you expose or add, making sure that they get invoked outside of any locks.

public class SafeDictionary<TKey, TValue>: IDictionary<TKey, TValue>
{
private readonly object syncRoot = new object();
private Dictionary<TKey, TValue> d = new Dictionary<TKey, TValue>();

public void Add(TKey key, TValue value)
{
lock (syncRoot)
{
d.Add(key, value);
}
OnItemAdded(EventArgs.Empty);
}

public event EventHandler ItemAdded;

protected virtual void OnItemAdded(EventArgs e)
{
EventHandler handler = ItemAdded;
if (handler != null)
handler(this, e);
}

// more IDictionary members...
}

Edit: The MSDN docs point out that enumerating is inherently not thread safe. That can be one reason for exposing a synchronization object outside your class. Another way to approach that would be to provide some methods for performing an action on all members and lock around the enumerating of the members. The problem with this is that you don't know if the action passed to that function calls some member of your dictionary (that would result in a deadlock). Exposing the synchronization object allows the consumer to make those decisions and doesn't hide the deadlock inside your class.

How can I make a thread safe dictionary

If your program is written in .NET, you can take a look at this related question regarding the best way of implementing a thread-safe Dictionary, with links and C# sample code…

.NET4.0: Thread-Safe Manner of Updating A Dictionary and Its Values

lock is good (and necessary; you were right to suspect that Interlocked would not suffice) but once you do that the Interlocked.Increment and Interlocked.Decrement are unnecessary. The issue with accessing a Dictionary<TKey, TValue> from multiple threads is that one thread could trigger a rebuild of the internal hashtable, then that thread gets swapped out mid-rebuild for another thread which now comes along and adds to the dictionary wreaking havoc on the internal structure of the dictionary.

Additionally, your implementation is good in that you lock on a private object rather than this. As chibacity pointed out, this lock object should be readonly though.

Be careful that you don't trick yourself into thinking that you've now made your dictionary bullet-proof in multi-threaded scenarios. For example, the following could happen:

Thread 1 looks up string "Hello, World!" in the dictionary, receives back the count 1.

Thread 1 is swapped out for Thread 2.

Thread 2 calls remove with key "Hello, World!" setting the count to 0.

Thread 2 is swapped out for Thread 1.

Thread 1 now thinks that the count is 1 but it is actually 0.

Finally, in .NET 4.0, you should consider using ConcurrentDictionary<TKey, TValue>. Note that this effectively eliminates the need to lock when calling instance-methods on the dictionary, but it does not eliminate the above scenario from occurring.

Thread safe way of reading a value from a dictionary that may or may not exist

Locking is required even for reading in the presence of concurrent writers. So yes, this is as good as it gets if you mutate the dictionary.

You can of course always create a copy of the entire dictionary each time something is written. That way readers might see an out-of-date version but they can safely read.

c# Is HashTable thread safe?

You are correct, HashTable and Dictionary are not thread safe. HashTable can be made (sort of) thread safe using the HashTable.Synchronized function. This creates a wrapper around the HashTable allowing only one writer and multiple readers to access HashTable. But.

The wrapper around the HashTable is not fully thread safe, one could iterate the collection while another thread could concurrently still change the collection resulting in an exception.

Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.

-- https://docs.microsoft.com/en-us/dotnet/api/system.collections.hashtable.synchronized?view=netcore-3.1

Depending on the situation I would pick a collection from the System.Collections.Concurrent namespace. Which is best described here: https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/

Bear in mind though that these collections are not the fastest - if speed is important I would recommend tailoring one to your specific needs.



Related Topics



Leave a reply



Submit