Multithreading in C#

Threading is an important concept in all development technologies. If we want to perform multiple operations concurrently, then threading is the best choice.

The classes which are used in multithreaded programming are defined in the System.Threading namespace.

There are two different types of multitasking:

  • Process-based multitasking.
  • Thread-based multitasking.
A program in execution is called as thread.

In process-based multitasking two or more programs runs in your computer concurrently. For example at a time you are working on ms-word and listening the music from media player.

In thread based multitasking environment, a single program can perform two or more tasks at once. For example, a text editor can be formatting text at the same time it checks the grammar.

The .NET Framework supports two types of threads:

  • Foreground threads.
  • Background threads.
When you create a thread, by default, it is a foreground thread, but you can change it to a background thread.

Important properties of thread

Example

using System;
using System.Threading;
namespace ConsoleApplication1
{    
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main Thread ID       = " + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Is thread alive      = "+Thread.CurrentThread.IsAlive);
            Console.WriteLine("Is background thread = "+Thread.CurrentThread.IsBackground);
            Console.WriteLine("Priority             = " + Thread.CurrentThread.Priority);
            Console.WriteLine("ThreadState          = " + Thread.CurrentThread.ThreadState);
            Console.WriteLine("CurrentCulture       = " + Thread.CurrentThread.CurrentCulture);
            Console.WriteLine("IsThreadPoolThread   = " + Thread.CurrentThread.IsThreadPoolThread);           
           
            Console.ReadLine();
        }
    }
}


Output:

Main Thread ID           = 9
Is thread alive             = True
Is background thread = False
Priority                         = Normal
ThreadState                 = Running
CurrentCulture            = en-US
IsThreadPoolThread   = False

The code shows some important properties of Thread. Each thread has their ID. You can get the ID by using ManagedThreadId property. You can get the state of thread by using ThreadState property (Stop, running, abort, etc). There are predefined threads in ThreadPool. IsThreadPoolThread property provides the information that whether a thread is from the thread pool or not.

Thread Priority

The Thread class provides the ThreadPriority enumeration. You can get or set the thread priority by using ThreadPriority enumeration.

ThreadPriority Enumeration has following values

  • Highest
  • AboveNormal
  • Normal
  • BelowNormal
  • Lowest

Creating Thread

Thread class is used to create thread. This class is available in System.Threading namespace.

Example

using System;
using System.Threading;
namespace ConsoleApplication1
{
    class ThreadDemo
    {
        string name;
        public int count;
        public ThreadDemo(string n)
        {
            name = n;
        }
        public void run()
        {
            Console.WriteLine("\t Child Thread started");
            do
            {
                Thread.Sleep(500);
                Console.WriteLine("\t count for " + name + " is =>" + count);
                count++;
            } while (count < 6);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("\n\n Main Thread started");
            Console.WriteLine();
            ThreadDemo obj = new ThreadDemo("Child Thread");
            Thread t = new Thread(new ThreadStart(obj.run));
            t.Start();
            do
            {
                Console.Write("*");
                Thread.Sleep(100);
            } while (obj.count != 6);
            Console.WriteLine();
            Console.WriteLine("Main Thread terminated");
            Console.ReadLine();
        }
    }
}


Run the application you will get the result something like given below.

Main Thread started
*        Child Thread started
*****    count for Child Thread is =>0
****     count for Child Thread is =>1
*****    count for Child Thread is =>2
*****    count for Child Thread is =>3
*****    count for Child Thread is =>4
*****    count for Child Thread is =>5
Main Thread terminated

Look the above code closely, you will that two functions runs simultaneously. The main function prints the “*” and the Run() function prints the count value. Run() method is written in ThreadDemo class. This run() is executed by Thread object t. Inside its Run( ) method, a do-while loop is present that that counts from 0 to 5. Sleep() is static method of Thread class that is used to suspend the execution of thread for the specified period of milliseconds.

Inside Main( ) method, a new Thread object is created as follows:

ThreadDemo obj = new ThreadDemo("Child Thread");
Thread t = new Thread(new ThreadStart(obj.run));


Here ThreadStart is a predefined delegate that is used to refer parameter less method.

t.Start() will start the execution of Run () method. Concurrently do-while loop that is written in main () method also executed.

Creating Multiple Threads

You can create multiple threads in many ways. In the given example we have created two threads but can create more than two. You can use any loop to create multiple thread. In the example, constructor public ThreadDemo(string n) is used to initialize and start the thread. Every thread shows the thread count in parallel.

Example

using System;
using System.Threading;
namespace ConsoleApplication1
{
    class ThreadDemo
    {
         int count;
         Thread t;
        public ThreadDemo(string n)
        {
            ThreadStart ts = new ThreadStart(run);
            t = new Thread(ts);
            t.Name = n;
            t.Start();
        }
        public void run()
        {
            do
            {
                Thread.Sleep(300);
                Console.WriteLine("\n{0} THREAD  started and count ={1} ", t.Name,count);
                count++;
            } while (count < 6);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main Thread started and ID= " + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine();
            ThreadDemo obj1 = new ThreadDemo("FIRST");
            ThreadDemo obj2 = new ThreadDemo("SECOND");         
           Console.ReadLine();
        }
    }
}


Run the application you will get the result something like given below.

Main Thread started and ID= 10
SECOND THREAD  started and count =0
FIRST THREAD  started and count =0
SECOND THREAD  started and count =1
FIRST THREAD  started and count =1
SECOND THREAD  started and count =2
FIRST THREAD  started and count =2
SECOND THREAD  started and count =3
FIRST THREAD  started and count =3
SECOND THREAD  started and count =4
FIRST THREAD  started and count =4
SECOND THREAD  started and count =5
FIRST THREAD  started and count =5

Due to system configuration, the output you see may differ from that shown here.

Passing Data to Threads

Till now we have used ThreadStart delegate to refer method in threading.

ThreadStart is a predefined delegate as follows:

public delegate void ThreadStart( )

Its return type is void and does not take any parameter. That’s why you cannot use ThreadStart delegate to call those methods which takes any parameter.

ParameterizedThreadStart is a delegate that is used to call those methods which takes a parameter.

public delegate void ParameterizedThreadStart(object obj)

It takes parameter as Object. Therefore you can pass any type as parameter while using ParameterizedThreadStart delegate in threading.

Example

using System;
using System.Threading;
namespace ConsoleApplication1
{
    class ThreadDemo
    {
        public void Run(object ob)
        {            
            Console.WriteLine("Current Thread ID ={0} ,{1}", Thread.CurrentThread.ManagedThreadId, ob);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main Thread started ");
            Console.WriteLine();
            ThreadDemo obj = new ThreadDemo();
            Thread t = new Thread(new ParameterizedThreadStart(obj.Run));
            t.Start("Welcome at TutorialRide");
            Thread.Sleep(200);           
            Console.WriteLine("Main Thread terminated  " );
            Console.ReadLine();
        }
    }
}


Using Thread.Join

Thread class has the Join() method that enables a thread to wait for another thread to complete execution. A better use of join method is that, when we use more threads in our application. When we are working with multiple threads, sometimes situation occur that second thread join the first thread after execution of first thread. A thread can wait for another thread to finish by calling its Join() method.

Example

using System;
using System.Threading;
class ThreadDemo
{
    int count;
    public Thread t;
    public ThreadDemo(string name)
    {
        count = 0;
        t = new Thread(this.Run);
        t.Name = name;
        t.Start();
    }
    void Run()
    {
        Console.WriteLine(t.Name + " started.");
        do
        {
            Thread.Sleep(600);
            Console.WriteLine(t.Name + ", count is " + count);
            count++;
        } while (count <=5);
        Console.WriteLine(t.Name + " terminated.");
    }
}
class Program
{
    public static void Main()
    {
        Console.WriteLine("Main thread started.\n");
        ThreadDemo obj1 = new ThreadDemo("Child Thread 1");
        obj1.t.Join();
        ThreadDemo obj2 = new ThreadDemo("Child Thread 2");            
        obj2.t.Join();     
        Console.WriteLine("Main thread terminated.");
        Console.ReadLine();
    }
}


Output:

Main thread started.
Child Thread 1 started.
Child Thread 1, count is 0
Child Thread 1, count is 1
Child Thread 1, count is 2
Child Thread 1 terminated.
Child Thread 2 started.                   The second thread started after finishing
Child Thread 2, count is 0            the first thread.
Child Thread 2, count is 1
Child Thread 2, count is 2
Child Thread 2 terminated.
Main thread terminated.