threading in c#

Threading in C# -Part 1

Threading is a very important concept among different programming languages. It helps to improve the performance of an application. In this article, we will explore threading in c# with some good examples which will help to understand the concept easily.

Process & Thread

A process is an executing program that OS provides when executing applications in parallel. A process creates a thread to do work, a thread actually gets CPU time to execute its operation. It also has the execution & current context details so that it can resume after preemption.

Multi threading in C#

When an application running in an OS, which uses a Process to run the application. A process can spawn threads that are lightweight than a process to run a program logic. Every process will be having at least one thread called the main thread. When a process creates more than 1 thread to run a program we call such an application “Multi Threaded Application“.  

A program performs better when multi threading is used. There are many scenarios where we can use a thread that will be the best fit for that application, similarly, in many other cases multi-threading may impact negatively.

A Multi threaded application performs better in multi-core machines than single-core machines since in a single-core machine multi threading comes at a cost of context switching. Multi threading improves the responsiveness & when used in Multicore machines.  

Multi threading would be a good choice for CPU-intensive tasks such as processing an image or operation involving a lot of computation. A multi threaded application should be designed properly so that it can be easily debugged. In most cases, thread synchronization, thread-safety, etc. becomes painful when the application becomes complex with multithreading.  

In DotNet, we can use “System.Threading” namespace to create a new thread & to use utilities associated with threading.   Let’s begin with the normal sequential execution process, here the code execution goes one after another in the below, example Method1 executes first and Method2 executes after Method1 completes. even though Method2 is not dependent on Method1, still it has to wait till it completes.  

using System;
using System.Threading;
namespace Learn
{
    class Learn
    {
        //long running code
        public static void Method1()
        {
            Console.WriteLine("Method 1 Started");
            //simulate long running program ,5s delaty
            Thread.Sleep(5000);
            Console.WriteLine("Method 1 Finished");
        }

        //quick code
        public static void Method2()
        {
            Console.WriteLine("Method 2 Started");
            Console.WriteLine("Method 2 Finished");
        }

        static void Main(string[] args)
        {
            Method1();
            Method2();
            Console.ReadLine();
        }
    }
}

Here method 2 waits till Method1 completes, so the out will be,  

Method 1 Started

Method 1 Finished

Method 2 Started

Method 2 Finished  

We can run Method1 in a separate thread so that the performance will be improved. Below is the example which shows the multi threading in c#

using System;
using System.Threading;
namespace Learn
{
    class Learn
    {
        //long running code
        public static void Method1()
        {
            Console.WriteLine("Method 1 Started");
            //simulate long running program ,5s delay
            Thread.Sleep(5000);
            Console.WriteLine("Method 1 Finished");
        }

        //quick code
        public static void Method2()
        {
            Console.WriteLine("Method 2 Started");
            Console.WriteLine("Method 2 Finished");
        }

        static void Main(string[] args)
        {
            ThreadStart del = new ThreadStart(Method1);
            Thread method1 = new Thread(del);
            method1.Name = "My New Thread";
            method1.Start();
            Method2();
            Console.ReadLine();
        }
    }
}

output:

Method 2 Started

Method 2 Finished

Method 1 Started

Method 1 Finished

The above output explains the order of execution of 2 methods. Assuming that method1 is CPU intensive task we ran method1 in a separate thread,method2 was free to execute. This was we can effectively utilize the CPU time. Below screenshot taken from Visual Studio to see multi threading in C#.

Creating a Thread in C#

 From the above example, we can see that creating a thread is easy, create a new thread by instantiating the class Thread. It expects the Threadstart delegate to be passed as an argument. Following are the different ways to create threads.

Thread newThread = new Thread(Method1);
Thread newThread = new Thread(new ThreadStart(Method1));
Thread newThread = new Thread(delegate() { Method1(); });
Thread newThread = new Thread(()=> { Method1(); });

Starting a Thread

Start() function can be used to start the thread.  

newThread.Start();  

We can also pass the argument of type objects to the thread if it needs an argument. The following code shows how to pass an argument to the thread. Thread expects an argument type of object. The below code expects a number n.

using System;
using System.Threading;
namespace Learn
{
    class Learn
    {
        public static void Method(object obj)
        {
            Console.WriteLine("Thread '{0}' is executing Method", Thread.CurrentThread.Name);
            int n = (int)obj;

            for (int i = 0; i < n; i++)
            {
                Console.Write("{0} ", i);
            }
            Console.WriteLine();
            Console.WriteLine("Thread '{0}'is Finished executing Method", Thread.CurrentThread.Name);

        }

        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "Main Thread";
            Console.WriteLine("Main method executed on{0}", Thread.CurrentThread.Name);

            Thread thread1 = new Thread(Method);
            thread1.Name = "My New Thread";
            thread1.Start(5);
            Console.ReadLine();
        }
    }
}

Threading in C#

Other main Properties

  • join() : If we want to wait for a thread to complete its task before moving further, we can use Thread.join(), which will halt the execution until the thread finishes its task.
  • Name: We can set the name for the thread to identify it.
  • IsAlive: We can check if the thread suspended or it is alive.
  • IsBackground: We can specify that the thread is Foreground or Background thread. A process terminates when all the foreground threads finished. Once the program terminates the background thread also terminates.

Call Back from Thread after Execution

We can use delegate to do a call back after completing the task.So we can wrap the function in class for this as explained below,

using System;
using System.Threading;
namespace Learn
{
    public delegate void MyDelegate(long sum);
    public class MyClass
    {
        private int _count;
        public MyDelegate callback;
        public MyClass(int count, MyDelegate callback)
        {
            this._count = count;
            this.callback = callback;
        }

        public void LongRunningJob()
        {
            long sum = 0;
            for (int i = 0; i < _count; i++)
            {
                sum += _count;
            }

            callback(sum);
        }

    }
    class Learn
    {

        static void Main(string[] args)
        {
            Console.WriteLine("Main Started");
            MyClass myClass = new MyClass(1000, (x) => { Console.WriteLine("Sum from thread={0}", x); });
            Thread myThread = new Thread(myClass.LongRunningJob);
            myThread.Start();
            Console.WriteLine("Main Completed");
            Console.ReadLine();
        }
    }
}
Threading in C#

Here we have a class where we have a long-running job, we can pass a delegate to the constructor of the class which will do a callback to the function after the job completes.

Thread Abort & Interrupt

Calling Thread.Abort() or Thread.Interrupt() results in ThreadAbortException and ThreadInterruptedException  respectively, thread code should catch this & handle the exception.  

Synchronization during thread calls

We need to ensure that part of the program logic where shared resources used should be thread-safe meaning when multiple threads are trying to access the same resource there could be a chance that we mess up this. Say for example when we use the static property in class & multiple threads are able to manipulate this at a time, so the data will be in an inconsistent state. There are different ways to address this problem, lets check one of them, Monitor class or lock.  

By using Monitor class we can acquire an exclusive lock on a critical section of the program thereby preventing multiple threads from executing simultaneously. Below is the code snippet of how to use Monitor class or lock.

public class MyClass
{
    private readonly object _lockObject = new object();

    public void MyMethod()
    {
        Monitor.Enter(_lockObject);

        //Critical Code Section
        //Only one thread is allowed to execute this section.

        try
        {
            //code
        }
        catch
        {
            //handle execptions
        }
        finally
        {
            //always release lock
            Monitor.Exit(_lockObject);
        }
    }

}
public class MyClass
{
    private readonly object _lockObject = new object();

    public void MyMethod()
    {

        lock (_lockObject)
        {
            //Critical Code Section
            //Only one thread is allowed to execute this section.
        }

    }

}

Leave a Reply