Multithreading in C#

What is Multithreading?

Multithreading in C# is a process to execute multiple threads simultaneously to run multiple programs or tasks at a time.

In C#, multithreading helps us to run multiple tasks parallelly or asynchronously.

In order to create a multithreading application, we need to import System.Threading namespace.

Let’s understand the concept of Synchronous and Asynchronous programming in C#.

Synchronous: In Synchronous programming, all the tasks run in a sequence. Here, the next task has to wait until the first task gets completed.

In simple words, synchronous means executing one or more tasks one after the other.

Pictorial representation of synchronous processing

threading in C#

Asynchronous: Asynchronous means executing multiple tasks simultaneously. Here, the second task doesn’t need to wait for the first task to get completed, they can run simultaneously.

Windows operating system is the best example of multitasking where we can run multiple applications like MS Word, Powerpoint, Media players, Web browser, etc. at the same time.

For every application to be launched, a new thread is generated in the system to run all these applications asynchronously.

Pictorial representation of multithreading

C# Multithreading

By default, every process in C# has at least one (Main) thread to run the application.

Example of synchronous programming (Single Threaded)

using System;
namespace SynchronousProgramming
{
    class Program
    {
        static void Main(string[] args)
        {
            Task1();
            Task2();
            Task3();
        }
        public static void Task1()
        {
            for(int i=1;i <= 3; i++)
            {
                Console.WriteLine($"Task1: i = {i}");
            }
        }
        public static void Task2()
        {
            for (int i = 1; i <= 3; i++)
            {
                Console.WriteLine($"Task2: i = {i}");
            }
        }
        public static void Task3()
        {
            for (int i = 1; i <= 3; i++)
            {
                Console.WriteLine($"Task3: i = {i}");
            }
        }
    }
}


Synchronous programming output
The output of the above C# program

In the above result, we can see that all the main thread executing all the tasks one after the other. Here, The next task needs to wait until the first task will get completed.

To overcome this problem, we can use multithreading to execute all the tasks parallelly.

Example of multithreading (Asynchronous programming)

using System;
using System.Threading;

namespace Multhreading
{
    class Program
    {
        static void Main(string[] args)
        {
            // Main Thread
            Thread mainThread = Thread.CurrentThread;
                   mainThread.Name = "Main Thread";

            Console.WriteLine($"{mainThread.Name} started");

            // Creating worker threads
            Thread thread1 = new Thread(Task1);
            thread1.Name = "Thread 1";

            Thread thread2 = new Thread(Task2);
            thread2.Name = "Thread 2";

            Thread thread3 = new Thread(Task3);
            thread3.Name = "Thread 3";
           
            // Executing the tasks
            thread1.Start();
            thread2.Start();
            thread3.Start();

            Console.WriteLine($"{mainThread.Name} ended");
            Console.ReadLine();

        }
        public static void Task1()
        {
            Console.WriteLine($"Task1 started using {Thread.CurrentThread.Name}");
            for(int i=1;i <= 3; i++)
            {
                Console.WriteLine($"Task1: {i} {Thread.CurrentThread.Name}");
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            Console.WriteLine($"Task1 completed using {Thread.CurrentThread.Name}");
        }
        public static void Task2()
        {
            Console.WriteLine($"Task2 started using {Thread.CurrentThread.Name}");
            for (int i = 1; i <= 3; i++)
            {
                Console.WriteLine($"Task2: {i} {Thread.CurrentThread.Name}");
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            Console.WriteLine($"Task2 completed by {Thread.CurrentThread.Name}");
        }
        public static void Task3()
        {
            Console.WriteLine($"Task3 started by {Thread.CurrentThread.Name}");
            for (int i = 1; i <= 3; i++)
            {
                Console.WriteLine($"Task3: {i} {Thread.CurrentThread.Name}");
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            Console.WriteLine($"Task3 completed by {Thread.CurrentThread.Name}");
        }
    }
}



Multithreading program result.
The output of the above C# multithreading program.

Here, the output of the above program may vary on different systems.

As we can see in the above output that all the tasks are executing asynchronously.

Multithreading allows for the maximum utilization of the CPU by running multiple programs concurrently.

The main advantage of multithreading is to make a user interface responsive.

What is Thread?

In C#, A  thread  is defined as the basic unit to which an operating system allocates CPU time to execute the logic of the program.
By default, every application or a program in .NET is started with a single thread called the main thread or the primary thread.
The main thread is used to create additional threads (Worker thread) when required to run multiple tasks concurrently.

Types of Threads in C#

In C#, there are two types of threads,  foreground  and   background   thread.

As we already know that to run a program we need at least one thread called the main thread.
If we create threads explicitly to run multiple methods those threads will become the child thread or worker thread for the main thread.

Foreground thread in C#

Foreground Thread: Foreground threads are the threads that keep on running to finish its task even the main thread quits or finished its task.

It is also known as worker thread and its lifespan doesn’t depend on the main thread.

A foreground thread prevents an application from being terminated until it’s done with the execution of the task.
By default, a thread is created as a foreground thread.

Example of foreground threads in c#.

using System;
using System.Threading;

namespace ForegroundThreadDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main thread started");

            // Creating foreground thread
            Thread workerThread = new Thread(Task1);
            workerThread.Name = "Worker Thread";
  
            // Executing the tasks
            workerThread.Start();

            Console.WriteLine("Main thread ended");
            Console.ReadLine();

        }
        public static void Task1()
        {
            Console.WriteLine($"Task1 started using {Thread.CurrentThread.Name}");
            for(int i=1;i <= 5; i++)
            {
                Console.WriteLine($"i = {i} {Thread.CurrentThread.Name}");
                //Pausing the thread execution for 2 seconds
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            Console.WriteLine($"Task1 completed using {Thread.CurrentThread.Name}");
        }
        
    }
}

Foreground Thread
The output of the above C# program.

In the above result, the foreground thread or worker thread continued execution and completed its task even the main thread was ended.

So, the lifespan of the foreground thread doesn’t depend upon the main thread or primary thread. It can alive without the main thread.

Background thread in C#

Background thread: By default, every thread we created explicitly in C# is a foreground thread.
To make a thread as a background thread, we have to set the  IsBackground  property of that particular thread to true.

The lifespan of the background thread depends upon the main thread. If the main thread quit then the background thread will also get terminated immediately.

In C#, The CLR is used to end the process once all the foreground thread belonging to a process has terminated.
After then all the other remaining background threads will be stopped immediately and prevent further execution of the assigned tasks.

Example of background threads in c#.

using System;
using System.Threading;

namespace BackgroundThreadDemo
{
    class Program
    {
        static void Main(string[] args)
        {          
         // Creating background thread
         Thread bgThread = new Thread(Task1);

         bgThread.IsBackground = true;

         bgThread.Name = "Background Thread";

        // Executing the tasks
         bgThread.Start();

        Console.WriteLine("Main thread quit");
      
        }
        public static void Task1()
        {          
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine($"i = {i} {Thread.CurrentThread.Name}");
                //Pausing the thread execution for 2 seconds
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }
            Console.WriteLine("Backgroung thread quit");
        }

    }
}

Background thread output
The output of the above C# program.

In the above result, we can see that once the main thread quit, the background thread also gets terminated immediately.

Hope you enjoyed this post. Thanks for visiting.

Leave a Reply

Your email address will not be published. Required fields are marked *

1 + one =