Multi Threading - Part1

 28-May-2013   NityaPrakash     MultiThreading    Comments  0

In this article, I will be revisiting the basic concepts of multi threading. I am going to talk about traditional old style thread creation and playing with ThreadPool. Thread is an independent execution path, that able to run simultaneously with other threads. Every application or program starts with minimum one thread which generally called �main� thread.

The CLR assigns each thread its own memory stack so the local variable are kept separate. All the threads in same process share the same memory space ( HEAP) but creates stacks for each thread.


        static void Main(string[] args)
        {
            Thread t = new Thread(DoWork);
            t.Start();
            DoWork();
            Console.Read();
        }

        static void DoWork()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.Write(i);
            }
        }
	//output:
	//0012341234

In this example DoWork() method was called in 2 threads, and variable �I� is being printed twice. So variable declared inside method which being called in each thread has local scope and being running in different thread, they have separate stack to manage the memory. However if variable declared out side the consuming method than it will be shared by all thread which executing DoWork() method. This situation brings the topic of thread safety. As long as threads are just reading the field or property than it is fine. If multiple methods are running various thread and modifying the static or global variable of class than result will be unpredictable as you wouldn�t be knowing which thread is being using the control that time. In that case, we need to acquire lock on the object being shared among threads.

Join Vs Sleep

There may be some cases when a specific thread should be called after a specific thread finish execution. Thread2 need to execute only, when thread1 process the data to use for thread2.


    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(Process1);
            Thread t2 = new Thread(Process2);
            Thread t3 = new Thread(Process3);

            t1.Start();
            t2.Start();
            t1.Join();
            t3.Start(); //t3 will not start until t1 finish execution.
            Console.Read();
        }

        static void Process1()
        {
            Console.WriteLine("Process 1 started");

            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                Console.Write("P1");
            }

            Console.WriteLine("Process 1 finished");
        }

        static void Process2()
        {
            Console.WriteLine("Process 2 started");

            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                Console.Write("P2");
            }

            Console.WriteLine("Process 2 finished");
        }

        static void Process3()
        {
            Console.WriteLine("Process 3 started");

            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                Console.Write("P3");
            }

            Console.WriteLine("Process 3 finished");
        }

    }

Output:

In this example we are asking thread to stop processing for 100 miliseconds. During each sleep mode it, thread doesn�t consume CPU resource and handover the CPU to other threads. There is another method called Thread.Yield() which hand over the CPU to other thread running on same processor while it is not the case with Thread.Sleep() methods

Passing Data to a Thread

Traditionally, ThreadStart delegate just takes one argument of object type. It can be type cast in appropriate type and can be used. We don�t need to use ThreadStart delegate to assign and execute the process:


    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(Process);
            t1.Start(" my process");
            Console.Read();
        }

        static void Process(object msg)
        {
            string message = (string)msg;

            Console.WriteLine("Process 1 started");

            for (int i = 0; i < 10; i++)
            {
                Thread.Yield();
                Console.Write(msg);
            }

            Console.WriteLine("Process 1 finished");
        }
        
    }

We can also pass data using Lambda Expression:



   class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>Process("abc", "This is test message"));
            t1.Start();
            Console.Read();
        }

        static void Process(string user,string message)
        {
            Console.WriteLine("User: " + user);
            Console.WriteLine("Message: " + message);
        }
        
    }

In this example we have advantage of passing multiple parameters to the function. There is another way to pass data to the thread as below:


            string user = "abc";
            string message = "This is test message";
            Thread t1 = new Thread(() =>
                        {
                            Console.WriteLine("User: " + user);
                            Console.WriteLine("Message: " + message);
                        });
            t1.Start();

In this scenario, one should be careful about modifying data after starting thread. These variable are shared. If any thread modify them, changes will be reflected to all threads. To resolve this issue, create local copy in the thread before using them. However, if we want to use the main thread variable in the newly created thread, than process should be thread safe and various synchronization technique should be used based on scenario and requirement.

Foreground Vs Background Threads

There is only difference in foreground and background threads is that application doesn�t exist until all foreground threads finish their processes, but application doesn�t wait for background thread to complete. In this case background will abort executing. By default, all explicitly created threads are foreground threads. If thread is background and there finally or using implemented( some resource cleanup stuff) than one should used Join method to wait that thread before it exit. If thread is created ourselves than we should use Join method and if created in Threadpool than Wait handle should be implemented.

Thread Priority

We can change priority of thread within the process it self using Priority properties. But at system level there are many process are running and Thread has limitation in the process level only. So, even though if we upgrade priority of any thread, but Priority of the process also precedence over thread. If priority of Process is low, it doesn�t going to impact by thread�s priority.

Exception Handling should be done inside the method being executed in thread. Thread started in any try catch block will not catch exception thrown in other thread. Global exception handling even Application.DispatcherUnhandledException and Application.ThreadException fire only for exception occurred in main UI thread. For other threads we must handle it manually in their own methods.


Nitya Prakash Sharma has over 10 years of experience in .NET technology. He is currently working as Senior Consultant in industry. He is always keen to learn new things in Technology and eager to apply wherever is possible. He is also has interest in Photography, sketching and painting.

My Blog
Post Comment

COMMENTS