C# Thread (Threading)

In c#, the thread is a basic unit of execution within the process, and it is responsible for executing the application logic.

 

By default, every application or program will carry one thread to execute the application logic, and that thread is called the Main thread. So, we can say that every program or application is by default a single-threaded model.

 

For example, in a Windows operating system, if we open Microsoft Excel and Word applications simultaneously, each application process will be taken care of by separate threads.

 

In c#, we need to import System.Threading namespace in our program to work with threads. Once we import System.Threading namespace, we can create or access the threads using Thread class.

 

Generally, in c# when we start a program execution, the Main thread will automatically create to handle the program logic. If we create any other threads in our program by using Thread class those will become child threads for the Main thread.

C# Access Main Thread

If we want to access the Main thread that is executing the current program code, we can get it by using CurrentThread property of the Thread class.

 

Following is the example of getting the main thread details using CurrentThread property of Thread class.

 

using System;
using System.Threading;

namespace TutlaneExamples
{
   class Program
   {
      static void Main(string[] args)
      {
         Thread t1 = Thread.CurrentThread;
         Console.WriteLine("Thread Id:{0}", t1.ManagedThreadId);
         Console.WriteLine("Is Background Thread:{0}", t1.IsBackground);
         Console.WriteLine("Thread Culture:{0}", t1.CurrentCulture);
         Console.ReadLine();
      }
   }
}

If you observe the above code, we imported System.Threading namespace to get the main thread details by using CurrentThread property of Thread class.

 

When we execute the above program, we will get the result below.

 

Thread Id:10
Is Background Thread:False
Thread Culture:en-IN

This is how we can access our application's main thread, which executes our program code based on our requirements.

 

In c#, the Main thread is responsible for executing the programming logic in a synchronous way that means one after another. If we want to execute a few tasks simultaneously (asynchronous way), we need to create the child threads in our application.

C# Create Thread

In c#, we can create a thread by extending the Thread class. To create a new thread, we need to pass ThreadStart delegate as a parameter to the Thread constructor, as shown below. Here, the parameter ThreadStart is the method executed by the new thread.

 

Once the thread is created, we need to call the Start method of Thread class to start the execution of the newly created thread.

 

// Create thread
Thread t1 = new Thread(new ThreadStart(PrintInfo));
// start newly created thread
t1.Start();

Here, PrintInfo is the method, and it will be executed when we start the newly created thread. Initially, when we create a thread that will be in the unstarted state, so we need to start the thread by using Start() method.

 

As we discussed, if we create any threads in our program by using Thread class those will become child threads for the Main thread.

 

Following is the example of creating the thread in c# using Thread class.

 

using System;
using System.Threading;

namespace TutlaneExamples
{
    class Program
    {
       static void Main(string[] args)
       {
          // Create child thread
          Thread t1 = new Thread(new ThreadStart(PrintInfo));
          // start newly created thread
          t1.Start();
          Console.WriteLine("Main Thread Completed");
          Console.ReadLine();
       }
       static void PrintInfo()
       {
         for (int i = 1; i <= 4; i++)
         {
            Console.WriteLine("i value: {0}", i);
         }
         Console.WriteLine("Child Thread Completed");
       }
    }
}

When we execute the above program, we will get the result below.

 

Main Thread Completed
i value: 1
i value: 2
i value: 3
i value: 4
Child Thread Completed

The above result shows that the Main thread and child thread started their execution simultaneously. The child thread continued its execution until it finished its task even after completion of the Main thread execution.

C# Thread Properties

The following table lists some of the most commonly used properties of Thread class to work with threads in c#.

 

PropertyDescription
CurrentContext It will return the current context in which the thread is executing.
CurrentThread It will return the currently running thread.
CurrentCulture It is useful to get or set the culture for the current thread.
CurrentUICulture It is useful to get or set the Resource Manager's current culture to look up culture-specific resources at run time.
IsAlive It is useful to get the execution status of the current thread.
IsBackground It is useful to get or set a value that indicates whether the thread is a background thread or not.
IsThreadPoolThread It will return a value that indicates whether the thread belongs to the managed thread pool or not.
ManagedThreadId It will return a unique identifier of the currently managed thread.
Name It is useful to get or set the name of the thread.
Priority We can get or set a value that indicates the scheduling priority of a thread.
ThreadState It is useful to get the state of the current thread.

C# Thread Methods

The following table lists some of the most commonly used methods of Thread class to work with threads in c#.

 

MethodDescription
Abort() This method is useful to terminate the thread.
AllocateDataSlot() It will allocate an unnamed data slot on all the threads.
AllocateNamedDataSlot() It will allocate a named data slot on all threads.
BeginThreadAffinity() It will notify a host that the managed code is about to execute the instructions that depend on the identity of the current physical operating system thread.
EndThreadAffinity() It will notify a host that the managed code has finished executing the instructions that depend on the identity of the current physical operating system thread.
Equals() It will determine whether the specified object is equal to the current object or not.
Finalize() It will ensure that the resources are freed and other cleanup operations are performed when the garbage collector reclaims the Thread object.
GetData() It is useful to retrieve the value from the specified slot on the current thread.
GetDomain() It will return the current domain in which the current thread is running.
GetHashCode() It will return the hash code of the current thread.
GetType() It will return the type of current instance.
Interrupt() It will interrupt a thread that is in the WaitSleepJoin thread state.
Join() It will make the thread finish its work or halt other threads until it completes work.
Resume() It will resume a thread that has been suspended.
Sleep() It will suspend the current thread for a specified amount of time.
Start() It will instruct the operating system to change the state of the current instance to Running.
Suspend() It will suspend the thread.
VolatileRead() It will read the value of a field, and that value is the latest written by any processor in a computer.
VolatileWrite() It will write a value to the field immediately so that the value will be visible for all processors in the computer.
Yield() It will yield the execution to another thread that is ready to run on the current processor.

C# Thread Life Cycle

In c#, each thread will have a life cycle, and it will start when we create an instance of the object using Thread class. Once the task execution of the thread is completed, then the life cycle of the thread will end.

 

At any point, the thread in c# will exist in any one of the following states.

 

StateDescription
Unstarted When we create the thread, that will be in the unstarted state.
Runnable When we call the Start() method, the thread will move to ready to run or runnable state.
Running It indicates that the thread is in a running state.
Not Runnable If the thread is in a not runnable state means there is a chance that the Sleep() or Wait() or Suspend() method is called on the thread or blocked by I/O operations.
Dead If the thread is in a dead state, it means the thread completes its task execution or is aborted.

Following is the example of knowing the lifecycle and states of thread in c#.

 

using System;
using System.Threading;

namespace TutlaneExamples
{
    class Program
    {
       static void Main(string[] args)
       {
          // Create child thread
          Thread t1 = new Thread(new ThreadStart(PrintInfo));
          Console.WriteLine("Thread State: {0}", t1.ThreadState);
          // Start newly created thread
          t1.Start();
          Console.WriteLine("Thread State: {0}", t1.ThreadState);
          // Suspend thread
          t1.Suspend();
          Console.WriteLine("Thread State: {0}", t1.ThreadState);
          // Resume thread to running state
          t1.Resume();
          Console.WriteLine("Thread State: {0}", t1.ThreadState);
          Console.ReadLine();
       }
       static void PrintInfo()
       {
          Console.WriteLine("Method Execution");
       }
    }
}

If you observe the above example, we used ThreadState property of Thread class to know the state of the thread, and we used Start(), Suspend(), and Resume() methods of Thread class to start, suspend and resume the execution of a thread.

 

When you execute the above program, you will get the result below.

 

Thread State: Unstarted
Thread State: Running
Thread State: Suspended
Thread State: Running
Method Execution

This is how we can change or vary the thread states in our application based on requirements.

C# Thread Example

Following is the example of managing the thread by using various methods of Thread class.

 

using System;
using System.Diagnostics;
using System.Threading;

namespace TutlaneExamples
{
   class Program
   {
      static void Main(string[] args)
      {
         Stopwatch sw = new Stopwatch();
         sw.Start();
         Thread t1 = new Thread(new ThreadStart(PrintInfo));
         t1.Start();
         t1.Join(); // Halt the execution till thread execution completed
         sw.Stop();
         TimeSpan ts = sw.Elapsed;
         string et = String.Format("{0}:{1}:{2}", ts.Hours, ts.Minutes, ts.Seconds);
         Console.WriteLine("TotalTime: " + et);
         Console.WriteLine("Thread Execution Completed");
         Console.ReadLine();
      }
      static void PrintInfo()
      {
         for (int i = 1; i <= 5; i++)
         {
            Console.WriteLine("Thread paused for {0} seconds", 4);
            Thread.Sleep(4000); // Make Thread Pause for 4 Seconds
            Console.WriteLine("i value: {0}", i);
         }
      }
   }
}

If you observe the above example, we used different methods (Start, Join, and Sleep) of the Thread class to manage the thread, and the Stopwatch functionality is used to calculate the thread execution time based on our requirements.

 

Here, we used Start() method to start the thread execution, the Join() method to halt the execution till the thread execution is completed, and the Sleep() method is used to pause the thread execution for 4 seconds.

 

When you execute the above program, you will get the result below.

 

Thread paused for 4 seconds
i value: 1
Thread paused for 4 seconds
i value: 2
Thread paused for 4 seconds
i value: 3
Thread paused for 4 seconds
i value: 4
Thread paused for 4 seconds
i value: 5
TotalTime: 0:0:20
Thread Execution Completed

This is we can manage the thread execution by using Thread class methods based on our requirements.

C# Destroy or Abort Thread

In c#, by using the Abort() method of the Thread class, we can end or abort the thread execution process. While terminating the threading process, the Abort() method will raise a ThreadAbortException in the thread on which it is invoked.

 

Following is the example of terminating the thread execution process in c#.

 

Thread t1 = new Thread(new ThreadStart(PrintInfo));
t1.Start();
t1.Join();

t1.Abort()

C# Thread Types

In c#, we have two types of threads are available, those are

 

  • Foreground Threads
  • Background Threads

C# Foreground Threads

As discussed, our program code execution will be taken care of by the Main thread. If we create new threads to execute some of the methods, those will become child threads for the Main thread, and our application will become a multithreaded application.

 

Foreground threads are the threads that will run until it finishes their work, even if the Main thread completes its process. So, the lifespan of foreground threads will not depend on the Main thread.

 

Following is the example of foreground threads in c#.

 

using System;
using System.Threading;

namespace TutlaneExamples
{
   class Program
   {
      static void Main(string[] args)
      {
         Thread t1 = new Thread(new ThreadStart(PrintInfo));
         t1.Start();
         Console.WriteLine("Main Thread Execution Completed");
      }
      static void PrintInfo()
      {
        for (int i = 1; i <= 3; i++)
        {
           Thread.Sleep(2000);
           Console.WriteLine("i value: {0}", i);
        }
        Console.WriteLine("Child Thread Execution Completed");
      }
   }
}

The above example shows that we created a new child thread (t1) and executed the PrintInfo method. In PrintInfo method, every time we are pausing the thread execution for 2 seconds using the Sleep method.

 

When you execute the above program, you will get the result below.

 

Main Thread Execution Completed
i value: 1
i value: 2
i value: 3

Child Thread Execution Completed

If you observe the above result, even after completion of Main thread execution, the child thread continued its execution and completed its work.

C# Background Threads

In c#, background threads are just the opposite of foreground threads. The background threads will quit their process immediately when the Main thread quits. Here, the lifespan of background threads will depend on the Main thread.

 

To make the thread a background thread, we need to set IsBackground property to true for that thread. Background threads are useful for any operation that should continue as long as an application is running, but these will not prevent the application from terminating.

 

Following is the example of creating a background thread by setting IsBackground property to true in c#.

 

using System;
using System.Threading;

namespace TutlaneExamples
{
   class Program
   {
      static void Main(string[] args)
      {
         Thread t1 = new Thread(new ThreadStart(PrintInfo));
         t1.Start();
         t1.IsBackground = true;
         Console.WriteLine("Main Thread Execution Completed");
      }
      static void PrintInfo()
      {
        for (int i = 1; i <= 3; i++)
        {
           Console.WriteLine("i value: {0}", i);
           Thread.Sleep(2000);
        }
        Console.WriteLine("Child Thread Execution Completed");
      }
   }
}

If you observe the above example, we created a new child thread (t1) and set IsBackground property to true to make the child thread (t1) a background thread.

 

When you execute the above program, you will get the result below.

 

i value: 1
Main Thread Execution Completed

 If you observe the above result, the child thread process quits immediately after completion of the Main thread execution.

C# Thread Overview

The following are the important points that you need to remember about threads in c#.

 

  • In c#, the thread is a basic unit of execution within the process, and it is responsible for executing the application logic.
  • By default, every program will carry one thread to execute the program logic, and that thread is called the Main thread.
  • In c#, to work with threads, we need to import the System.Threading namespace in our program. 
  • After importing the System.Threading namespace in our program, we can create or access the threads using the Thread class.
  • In c#, the Main thread will automatically create to handle the program logic. If we create any other threads in our program using the Thread class, those will become child threads for the Main thread.
  • In c#, each thread will have a life cycle, and it will start when we create an instance of the object using the Thread class.
  • In c#, by using the Abort() method of the Thread class, we can end or abort the thread execution process.
  • In c#, two types of threads are available; those are foreground threads and background threads.
  • Foreground threads are the threads that will run until it finishes their work, even if the Main thread completes its process.
  • Background threads will quit their process immediately when the Main thread quits.

In the following chapters, we will learn more about using multiple child threads with examples.