Monday, 18 March 2013

Thread Safety


Multi-threaded applications give a big boost to Code’s Performance and Scalability. But often times we need to be careful while using Thread-unsafe collections in these scenarios.

Here, we’ll know how to ensure proper dynamic allocation of memory to thread-unsafe collections and to perform Thread-Safe updates in them.



While updating values into a collection, memory allocation dynamically increases (doubles) once you reach its maximum capacity. This happens smoothly in Single-Threaded applications. But when you update Thread-unsafe collections via multiple threads, at rare times, CLR wouldn't be able to increase the allocated capacity for a collection when multiple threads simultaneously update the thread-unsafe collection.

Here is an example: Consider your collection has 31 values in it. Its current capacity is 32. In a single-threaded application, the next value-update will automatically resize the collection from 32 to 64. But consider a multi-threaded application - 2 threads simultaneously update values into the collection. So the memory shoots up from 31 to 33 without resizing the collection’s size to 64. At such instances (rare though), you’ll get a System.ArgumentException: Source array was not long enough.

Refer to this post on Array Resizing for more details: Array Resizing Optimization

To tackle the dynamic resizing problem, it would be better if you can specify the approximate size of the collection during its declaration. This will reduce the number of resizings drastically and reduces the probability of such an exception occurring. Another remedy is to just use a thread-safe collection.

The best way to perform thread-safe updates to a thread-unsafe collection is to lock the updates for variables that are shared across multiple threads (Globally scoped for the threads). Well, locking defeats the purpose of multi-threadedness. But you still can do safe updates to thread-unsafe collections that are local to each thread!

C# Experiments: Thread Safety (Part 1)
 



The code typed-in during the tutorial is as follows for your reference:-

            var serialA = new List<long>();
            var parallelA = new List<long>();
            var internalVars = new List<long>();

            parallelA.Capacity = 10000000;
            internalVars.Capacity = 10000000;

            for (long i = 0; i < 10000000; i++)
                serialA.Add(i);

            Parallel.For(0, 10000000, delegate(long i)
            {
                //Local Computations going on
                long internalVar = i + i;
                //internalVars.Add(internalVar);

                lock (parallelA)
                {
                    parallelA.Add(i);
                }
                lock (internalVars)
                {
                    internalVars.Add(internalVar);
                }
            });




Thank you for reading this post and watching the videos. Please Subscribe, Comment and Rate the channel if you liked the videos.

Goto C# Experiments to find more of such content! Thanks again!