Thread-Safe Generic Dictionary

The following question was posted on MSDN forums last night and I thought I’d take a little time to answer this considering my apparent threading affinity (*cough*). Here was the question:

“Could someone give me a pointer as to how I might implement a thread safe wrapper around a genric dictionary? I’ve written thread-safe dictionaries in C# 1.x by inheriting from the DictionaryBase but I’m a bit stumped as to how to acheive this using Generics.”

I can certainly understand the complaint here. It comes from the fact that Microsoft apparently didn’t think anyone would need thread-safe generic collections — or if you did, you should do your own work on this. Think I’m wrong? Consider this link, which states:

A System.Collections.Generic.Dictionary<,> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

What this means is that you have some limited options. 1) Create a sub-class of System.Collections.Generic.Dictionary, 2) Create a utility class for modifying the collection safely, or 3) Creating your own thread-safe dictionary from scratch.

Lets consider these one by one.

The first option: Sub-Class
This seems a bit rediculous. Your methods might look something like the following:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ThreadedGenerics {
  class ThreadSafeDictionary : Dictionary {
    public new void Add(T key, U value) {
      // Add your preferred thread locking mechanism here
       base.Add(key, value);
      // unlocking here
    }
    // TODO : Remaining Method Implementations
  }
}

or in VB.NET :

Imports System.Threading
Imports System.Collections.Generic
Public Class ThreadSafeDictionary(Of T, U)
    Inherits Dictionary(Of T, U)
    Public Shadows Sub Add(ByVal key As T, ByVal value As U)
        ' Add your preferred thread locking mechanism here
        MyBase.Add(key, value)
        ' unlocking here
    End Sub
    ' TODO : Remaining Method Implementations
End Class

This is obviously silly because we have to override all of our functionality anyway only to wrap the call in a critical section. You should lock the underlying collection as well, but that’s up to you to decide which method you prefer.

Additionally you have to qualify the method ‘overrides’ with “New” (Shadows in VB.NET) instead of override because Dictionary<,> didn’t mark the functions as virtual. Lets go ahead and scratch this option off the list. It just doesn’t make a lot of sense and violates OO.

The second option: Create a Utility Class

This method seems to make a bit more sense. You simply create a utility class to do all the work for you and do the wrapping. Its cleaner than the “inheritance” method. (I hesitate to call anything inheritance when you can’t override the functionality but rather follow a hide-recall pattern.) This would look something like this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace NewWinFormsFeatures
{
    public class ThreadSafeDictionaryUtility
    {
       Dictionary dict;
       public ThreadSafeDictionaryUtility() {
            dict = new Dictionary();
        }
        public void SafeAdd(T key, U value) {
            // Add your preferred thread locking mechanism here
            dict.Add(key, value);
            // unlocking here
        }
        // TODO : Remaining Method Implementations
    }
}

or in VB.NET

Imports System.Threading
Imports System.Collections.Generic
Public Class ThreadSafeDictionaryUtility(Of T, U)
    Private dict As Dictionary(Of T, U)
    Public Sub New()
        Me.dict = New Dictionary(Of T, U)
    End Sub
    Public Sub SafeAdd(ByVal key As T, ByVal value As U)
        ' Add your preferred thread locking mechanism here
        Me.dict.Add(key, value)
        ' unlocking here
    End Sub
End Class

This should work pretty well but it isn’t the most efficient way to get what you want. It does, however, prevent you from performing much implementation. You basically only provide the implementation methods you want and you simply wrap them into a critical section or object lock.

The third option: Rolling your own

This last option requires you to create your own implementation from scratch. This would require you to create a class that implemented the IDictionary<,> interface (and any others that you want to implement such as ISerializable). I wont get into details here because to do this right, you really need to do a lot of work and its already 3am here 🙂 What I will say is that Microsoft does state that DictionaryBase is not thread safe. What it does use is the BeginCriticalRegion and EndCriticalRegion methods to let the host know that exceptions in portions of the “add” code may be damaging to other code in the AppDomain. After waking up this morning and reviewing this code (per a very kind individual who bluntly pointed out my error) I feel its neccessary to write an explaination of what those methods do and when its not appropriate. BeginCriticalSection and EndCriticalSection around the ENTIRE Dictionary.Add method would be inappropriate. Where it would be appropriate to use these functions is in this third option — rolling your own. You want it around the very small portion of the code that does the array shifting and modifying of the underlying value. Otherwise, in the case of wrapping it around the Dictionary.Add method, something as simple as an invalid argument passed into your thread-safe class may cause the entire appdomain to shut down.

HTH.

Be Sociable, Share!

    One Thought on “Thread-Safe Generic Dictionary

    1. In modo che non è semplicemente

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Post Navigation