Thread safety and adding items to dictionaries

by Damiaan Peeters 13. August 2013 14:52

I was looking at some code from Zack Owens “Multi Tenancy Sample”.  He has some clever code, a ThreadSafeDictionary with a GetOrAdd method. I love the idea!  (code below for my own reference)

The problem with a dictionary, is that – apparently - .Net puts somewhere a system wide lock to ensure thread safety on a dictionary anyway.  That’s the reason that, if you are working with huge dictionaries with lots of READS, you might bump into some performance issues.  In such cases, you could (and should) use the ConcurrentDictionary from the System.Collections.Concurrent namespace.  And if you are looking at this class, visit the BlockingCollection from the same namespace also, still trying to wrap my head around it, but it is ultra important.  You just feel it when reading through the MSDN article.

   /// DON’T USE THIS CODE – You probably want a System.Collections.Concurrent.ConcurrentDictionary

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

   /// <summary>
   /// Dictionary that has a "GetOrAdd" method that is thread-safe
   /// </summary>
   /// <typeparam name="TKey">Dictionary key</typeparam>
   /// <typeparam name="TValue">Dictionary value</typeparam>
   public class ThreadSafeDictionary<TKey, TValue> : Dictionary<TKey, TValue>
   {
       /// <summary>
       /// Lock for adding values
       /// </summary>
       private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();

       /// <summary>
       /// Gets a value or adds the value in a thread-safe way
       /// </summary>
       /// <param name="key">Key in the dictionary</param>
       /// <param name="defaultValue">Delegate that will get the value</param>
       /// <returns>Value from the dictionary with given <paramref name="key"/></returns>
       public TValue GetOrAdd(TKey key, Func<TValue> defaultValue)
       {
           // enter read lock
           this.cacheLock.EnterReadLock();

           try
           {
               // test if value is in the dictionary
               if (this.ContainsKey(key))
                   return this[key];
           }
           finally
           {
               // exit read lock
               this.cacheLock.ExitReadLock();
           }

           // enter write lock
           this.cacheLock.EnterWriteLock();
           try
           {
               if (!ContainsKey(key))
                   this.Add(key, defaultValue());
               return this[key];
           }
           finally
           {
               // exit write lock
               this.cacheLock.ExitWriteLock();
           }
       }
   }

Who.I.am

Certified Umbraco, .net and Azure developer, seo lover. Magician in my spare time.

Month List