Tuesday, May 29, 2012

Dictionary is not thread safe

No surprises, dictionary is not thread safe.  But what if you're using it with guaranteed unique keys; ie each thread is guaranteed to be accessing it with a key unique to only that thread?

Here's a test:


private static readonly Dictionary<string, string> dictionary = new Dictionary<string, string>();

     public static void Main(string[] args)
        {
            var threads = new List<Thread>();
            for (int threadNumber = 0; threadNumber < 100; threadNumber++)
            {
                int number = threadNumber;
                var thread = new Thread(
                    () =>
                    {
                        for (int index = 0; index < 1000; index++)
                        {
                            Console.WriteLine("Thread" + number + " index " + index);
                            var key = Guid.NewGuid().ToString();
                            dictionary.Add(key, "Value");
                            var dynamicValue = Guid.NewGuid().ToString();
                            dictionary[key] = dynamicValue;
                            Debug.Assert(dictionary[key] == dynamicValue);
                        }
                    });
                threads.Add(thread);
                thread.Start();
            }

            foreach (var thread in threads)
            {
                thread.Join();
            }
        }

So, as you can see, this is creating a bunch of threads that all hammer the dictionary adding and editing and then asserting everything is as it should be. This runs fine with no exceptions. Or does it...

Comment the Console.WriteLine and it no longer runs...


So what is happening here?  As the dictionary gets larger the it will need to change its internal storage to increase its size, when this occurs another thread will either corrupt it or access stale data. So bad news.

The morale of the story is always add a Console.WriteLine before accessing a dictionary. Just kidding. If you think there will be any sort of multi-thread contention use a ConcurrentDictionary instead.  Just simply by thinking each thread accessing the dictionary using a guaranteed unique key will not suffice.

No comments:

Post a Comment