ConcurrentDictionary vs Hashtable.Synchronized

Comparison of collections in multithread environment

  • Share

Basically all Dictionary collections in .NET internally implement Hashtable wrapped, so in terms of mechanism they are pretty much the same. The difference is that Dictionary exposes strong types while Hashtable uses object-object keyvalue pair which is much harder to work with because you need to know what is the actual type of the object stored in a key or value. Often casting will probably be required.

In multithread code environment locking is considered by default when accessing any shared resource.
For most of the time this is some kind of object or collection.
Collections are tricky because you will run into and exception if one thread reads collection while the other one is modifying.

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

namespace ThreadCollection
{
    class ProgramHashtable
    {
        static Hashtable sharedList = Hashtable.Synchronized(new Hashtable());
        static void Main(string[] args)
        {
            //Initial load of 10 elements
            for (int i = 0; i < 10; i++)
            {
                sharedList.Add(Guid.NewGuid(), new object());
            }

            //Reading thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.Clear();
                    foreach (var key in sharedList.Keys)
                    {
                        Console.WriteLine(key.ToString());
                    }
                    Thread.Sleep(1);
                }
            }).Start();

            //Writing thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.ReadLine();
                    sharedList.Add(Guid.NewGuid(), new object());
                }
            }).Start();

        }
    }
}

    

For sure you will run into InvalidOperationException with message that collection is modified because enumeration operation is not thread safe by default.

Thread Hashtable Exception

This is because both threads are accessing shared collection at the same time, and write thread has changed the enumeration while the other one was reading. Reading state becomes invalid then and exception is thrown.

Since .Net Framework 1.1 this problem was solved by using lock. You simply use and object instance for locking and perform operation you want to make thread safe. Practically, when one thread performs lock others are waiting for lock to be released.

This way you ensure that only one thread is working with the shared collection. If locking is not involved it might cause application to work unexpectedly.

However, some collections like Hashtable provide wrappers for thread-safe operations, but this does not mean you do not need locking when enumerating through collection.

It is only for atomic operations, which enumeration is certanly not as it is executed in a loop. If you run the following code, which tries to write to Hashtable when you press enter key, you will probably get an exception. However, it might happend right in the time when reading is done, so keep pressing enter key and you'll definitely get en exception thrown.

This wrapper provides SyncRoot object for thread synchronization, but does not explicitly perform lock for enumeration. You will still have to perform lock when working with wrapped Hashtable if you are ittereating through it.

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

namespace ThreadCollection
{
    class ProgramHashtableLock
    {
        static Hashtable sharedList = Hashtable.Synchronized(new Hashtable());
        static void Main(string[] args)
        {
            //Initial load of 10 elements
            for (int i = 0; i < 10; i++)
            {
                sharedList.Add(Guid.NewGuid(), new object());
            }

            //Reading thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.Clear();
                    lock (sharedList.SyncRoot)
                    {
                        foreach (var key in sharedList.Keys)
                        {
                            Console.WriteLine(key.ToString());
                        }
                    }
                    //Give some time to other threads to kick in
                    Thread.Sleep(1);
                }
            }).Start();

            //Writing thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.ReadLine();
                    lock (sharedList.SyncRoot)
                    {
                        sharedList.Add(Guid.NewGuid(), new object());
                    }
                }
            }).Start();

        }
    }
}

    

Starting from .Net Framework 4 completely new namespace with thread safe objects which implement self locking. My favorite is ConcurrentDictionary. It provides strongly typed thread-safe collection which can be quried, something that hashtable does not have.

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

namespace ThreadCollection
{
    class ProgramConcurrentDictionary
    {
        static ConcurrentDictionary<Guid,Object> sharedList = new ConcurrentDictionary<Guid,object>();
        static void Main(string[] args)
        {
            //Initial load of 10 elements
            for (int i = 0; i < 10; i++)
            {
                sharedList.AddOrUpdate(Guid.NewGuid(), new object(), (key, oldValue) => new object());
            }

            //Reading thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.Clear();

                    foreach (var key in sharedList.Keys)
                    {
                        Console.WriteLine(key.ToString());
                    }
                    //Give some time to other threads to kick in
                    Thread.Sleep(1);
                }
            }).Start();

            //Writing thread
            new Thread(() =>
            {
                while (true)
                {
                    Console.ReadLine();
                    sharedList.AddOrUpdate(Guid.NewGuid(), new object(), (key, oldValue) => new object());
                }
            }).Start();

        }
    }
}

    

Unless you are targetting .NET Framework 2.0 or bellow there is really no need to stick with Hashtables as is becoming obsolete in new framework versions.

Regarding other thread-safe collection from System.Collections.Concurrent namespace you can check in msdn online documentation

References

  • Share

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.

Comments for this article

comments powered by Disqus