Tuesday, 24 December 2013

Multithreading or threading whichever that is (Part 2)

 When a thread is created, the OS (operating system) also assigns to the thread its own execution stack, memory heap and all the other bells and whistles that is necessary for the execution of the action delegate passed to it. But since there is no way to get the return value from a thread and since there is no standard way to communicate with the thread once it has been been started, this necessitates that the thread must interact in some way with the main thread by either writing to or copying from its memory. This creates a situation known as Shared State.

Due to the fact that the operating system switches threads at non-deterministic intervals, a thread can be switched by the OS when the time slice assigned to it has exhausted. In a situation whereby the thread is writing to the Shared State and that thread is switched out, this situation will invalidate the shared state and hence results in State corruption and therefore incorrect data because the data maybe completely over-written and consumed by another thread under the assumption that the data is correct.

To avoid this scenario, the most popular way to handle this situation is for the thread to lock the shared state until it finishes its operation in the state. This ensures that so far the thread is still executing that part of the shared state code, no other thread will have access to execute the same code at the same time thereby maintaining the state. But the use of the 'lock' keyword is not the only way to write a thread-safe code, other ways include using Mutex, Monitor among others.

Before we continue, lets take a break by looking at an example.


using System.Threading;
using System.Threading.Tasks;
 
namespace ConsoleTests
{
    class Program
    {
        private static object _locker = new object();
        private static int someToCalculate = 1000;
        private static int result = 0;
 
        static void Main(string[] args)
        {
            //create  a new thread here
            new Thread(Calculate).Start();
 
            //call the same action method that was part to the above created thread here.
 
            Calculate();
           
            Console.WriteLine("The total sum of numbers in {0} is {1}", someToCalculate, result);
            Console.WriteLine();
            Console.WriteLine();
 
            Console.ReadLine();
        }
 
        private static void Calculate()
        {
            lock (_locker)
            {
                //reset the result variable
                result = 0;
                
                //create a temp variable that will be used to do the calculation
                var temp = 0;
 
                for (int i = 0; i < someToCalculate; i++)
                {
                    temp += i;
                    Console.Write(temp + ", ");
                }
 
                result = temp;
            }
        }
    }
}


Yeah I know that there are better ways to write the above simple code but my aim is to make it as self explanatory as possible. If we look at the above code, we will see that the private method Calculate was called in two different threads -  the main thread and the artificial one we created for the purpose of running the Calculate action method. On closer look at the calculate method you will see that it depends on one private variable result (actually its two but since the _someCodeToCalculate was only read from we will ignore it at the moment). So in order not for us to get incorrect data, we used the 'lock' keyword and excluded it to only one thread at a time. Thereby making sure that a safe-state is maintained.

No comments:

Post a Comment