1

I'm synchronizing some threads using a dictionary of ManualResetEvents. It looks something like this. My question is, Is it thread-safe to call a getter/indexer of the dictionary like this? Should I call the getter from the context of a lock and store the value in a local variable?

Enum Type

enum RecvType
{
    Type1,
    Type2
    //etc...
}

Dictionary of ManualResetEvents

Dictionary<RecvType, ManualResetEvent> recvSync;

Wait operation

 void WaitForRecv(RecvType recvType, int timeout = 10000)
 {
    if (!recvSync[recvType].WaitOne(timeout))
    {
        throw new TimeoutException();
    }
        
    // do stuff
 }

EventHandler (called from another thread)

void RecvDone(object sender, RecvType recvType)
{
    recvSync[recvType].Set();
}

EDIT - clarify dictionary population

Dictionary Instanciation

public MyClass()
{
    recvSync = new Dictionary<RecvType, ManualResetEvent>();
    // populate dictionary (not modified after here)
    socketWrapper.RecvDone += RecvDone;
}
stevep
  • 167
  • 1
  • 7
  • 1
    Why dont you just use ConcurrentDictionary? – Clemens Feb 15 '22 at 16:23
  • If a thread is modifying the dictionary while another is reading it, this is not safe. If you populate the dictionary in one thread before any other threads read it, it will be safe. If the former (not safe) you could use `ConcurrentDictionary`. – Matthew Watson Feb 15 '22 at 16:23
  • Hadn't heard of ConcurrentDictionary before. This is in fact a prepopulated dictionary (only reads after the constructor), but since ConcurrentDictionary is apparently built for this kind of operation, I'll just use that. Thanks! – stevep Feb 15 '22 at 16:27
  • @stevep If you are not modifying the dictionary while other threads are reading it, there's no need to use ConcurrentDictionary (it will be slower). The [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-6.0) explicitly states: `"A Dictionary can support multiple readers concurrently, as long as the collection is not modified"` – Matthew Watson Feb 15 '22 at 16:42
  • @MatthewWatson Another lesson in just checking documentation *forehead smack* – stevep Feb 15 '22 at 17:08

1 Answers1

1

According to the documentation:

A Dictionary<TKey,TValue> can support multiple readers concurrently, as long as the collection is not modified.

So your pattern of usage is OK, regarding thread-safety. The behavior of a "frozen" Dictionary<K,V> when multiple threads are reading it, is well defined.

You could consider communicating your intentions more clearly by using an ImmutableDictionary<K,V> instead of a normal Dictionary<K,V>, but that clarity would come with a cost: Finding an element in an ImmutableDictionary<K,V> is ~10 times slower.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104