Table of contents
1.
Introduction
2.
C# Thread Properties
3.
Example
3.1.
C#
4.
C# Thread Methods:
4.1.
Start()
4.2.
Join()
4.3.
Sleep()
4.4.
Abort()
4.5.
Interrupt()
4.6.
C#
5.
Types of Threads in C#
5.1.
Foreground Threads
5.1.1.
Key Characteristics of Foreground Threads
5.1.2.
Example
5.2.
C#
5.3.
Background Threads
5.3.1.
Key Characteristics of Background Threads
5.3.2.
Example 
5.4.
C#
6.
Frequently Asked Questions
6.1.
What happens if a background thread is running when the application closes?
6.2.
Can a background thread be converted to a foreground thread?
6.3.
Is it possible to prioritize one foreground thread over another?
7.
Conclusion 
Last Updated: Jun 12, 2024
Easy

Threads In C#

Author Ravi Khorwal
0 upvote

Introduction

In C#, a thread is a small unit of execution that can run independently within a program. Threads allow you to perform multiple tasks simultaneously, which makes your programs more efficient & responsive. 

Threads In C#

In this article, we will discuss the fundamentals of C# threads, including their properties, methods, & types. 

C# Thread Properties

Threads in C# have several important properties that allow you to control & monitor their behavior. Some of the key properties include:

  1. IsAlive: This property returns a boolean value indicating whether the thread is currently running or has been started.
     
  2. IsBackground: This property determines whether the thread is a background thread or a foreground thread. Background threads do not prevent the application from terminating, while foreground threads do.
     
  3. Name: This property allows you to assign a name to the thread, making it easier to identify & debug.
     
  4. Priority: This property sets or retrieves the priority of the thread, which determines how much CPU time it gets relative to other threads.
     
  5. ThreadState: Provides the current state of a thread, such as Running, Suspended, or Stopped. This property is essential for controlling thread flow and handling synchronization issues.

Example

  • C#

C#

using System;
using System.Threading;

class Program
{
static void ThreadMethod()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Thread Proc: {0}", i);
Thread.Sleep(500);
}
}

static void Main()
{
Thread t = new Thread(new ThreadStart(ThreadMethod));
t.IsBackground = true; // Setting the thread as a background thread
t.Start();

for (int i = 0; i < 4; i++)
{
Console.WriteLine("Main thread: Do some work.");
Thread.Sleep(500);
}
Console.WriteLine("Main thread: Call Join(), to wait until ThreadMethod ends.");
t.Join();
}
}

Output

Thread Proc: 0
Main thread: Do some work.
Thread Proc: 1
Main thread: Do some work.
Thread Proc: 2
Main thread: Do some work.
Thread Proc: 3
Main thread: Do some work.
Thread Proc: 4
Main thread: Call Join(), to wait until ThreadMethod ends.
Thread Proc: 5
Thread Proc: 6
Thread Proc: 7
Thread Proc: 8
Thread Proc: 9

In this code, we configure a thread to run in the background and use the Join method to ensure that the main thread waits for the background thread to finish before it exits.

 

C# Thread Methods:

C# threads come with a variety of methods that allow you to control their execution. Some of the most commonly used thread methods include:

Start()

This method starts the execution of the thread. Once started, the thread will run independently of the main program thread.

Thread thread = new Thread(SomeMethod);
thread.Start();

Join()

This method blocks the calling thread until the thread on which it is called completes its execution. It is often used to ensure that the main program waits for a thread to finish before continuing.

thread.Join();

Sleep()

This method pauses the execution of the current thread for a specified amount of time. It is often used to introduce delays or to allow other threads to execute.

Thread.Sleep(1000); // Pause for 1000 milliseconds (1 second)

Abort()

This method aborts the thread, forcing it to stop its execution immediately. However, it is generally recommended to avoid using Abort() and instead use more graceful means of stopping a thread, such as using a flag or cancellation token.

thread.Abort(); // Not recommended

Interrupt()

This method interrupts the thread, causing it to throw a ThreadInterruptedException if it is currently blocked or sleeping. This can be used to request a thread to stop its execution gracefully

thread.Interrupt();


These are just a few of the many methods available for working with threads in C#. By using these methods effectively, you can control the execution & synchronization of your threads.

Let’s look at an example where we will be using all these methods : 

  • C#

C#

using System;
using System.Threading;

class Program
{
static void Main()
{
Thread t = new Thread(new ThreadStart(Run));
t.Start();
Thread.Sleep(2000); // Main thread pauses, allowing t to do some work
t.Interrupt();
t.Join(); // Wait for t to finish
Console.WriteLine("Thread t has ended!");
}

static void Run()
{
try
{
while (true)
{
Console.WriteLine("Thread running...");
Thread.Sleep(1000);
}
}
catch (ThreadInterruptedException)
{
Console.WriteLine("Thread interrupted!");
}
}
}

Output

Thread running...
Thread running...
Thread interrupted!
Thread t has ended!


In this code, the main thread starts another thread t, which runs indefinitely until it is interrupted. 

Types of Threads in C#

In C#, there are two main types of threads: foreground threads & background threads. 

We need to understand the differences between these thread types seriously, for managing the behavior & lifecycle of our application.

Foreground Threads

Foreground threads are the default type of threads in C#. They keep the application running until all foreground threads have completed their execution. The application will not terminate until all foreground threads have finished, even if the main thread has completed.

Key Characteristics of Foreground Threads

  1. Persistence: A foreground thread keeps the application running as long as it is active. The application will only close once all foreground threads have terminated.
     
  2. Priority: They can be assigned different priorities depending on the urgency of their tasks. Higher priority ensures more CPU time compared to other threads.
     
  3. Resource Management: Since foreground threads can delay the application's termination, they need careful management to ensure they do not consume unnecessary resources or cause the application to hang indefinitely.

Example

  • C#

C#

using System;
using System.Threading;

class Program
{
static void Main()
{
Thread foregroundThread = new Thread(new ThreadStart(LongTask));
foregroundThread.Start();

Console.WriteLine("Main thread is completing. Waiting for the foreground thread to finish.");
foregroundThread.Join(); // Ensures the main thread waits for the foreground thread to finish
Console.WriteLine("Foreground thread has completed, application will now close.");
}

static void LongTask()
{
Console.WriteLine("Foreground thread starts.");
Thread.Sleep(5000); // Simulates a long task
Console.WriteLine("Foreground thread is still running, processing data...");
Thread.Sleep(5000); // Continues to simulate a long task
Console.WriteLine("Foreground thread has finished processing.");
}
}

Output

Main thread is completing. Waiting for the foreground thread to finish.
Foreground thread starts.


In this example, the foregroundThread performs a task that takes significant time. The use of Join() on the main thread ensures that the application waits for the foreground thread to complete all its tasks before terminating. 

Note : Foreground threads are useful when you have critical tasks that must complete before the application can safely terminate. However, if a foreground thread becomes unresponsive or enters an infinite loop, it can prevent the application from closing properly.

Background Threads

Background threads, on the other hand, do not prevent the application from terminating. When the main thread or all foreground threads complete their execution, the application will terminate, regardless of whether any background threads are still running.

Key Characteristics of Background Threads

  1. Non-blocking: Background threads allow the application to terminate even if these threads are still running. This is crucial for tasks like logging, monitoring, or periodic checks that do not need to block the application's exit.
     
  2. Resource Usage: They generally have lower priority and should be designed to consume minimal resources to avoid affecting the performance of the main application.
     
  3. Automatic Termination: When the main application closes, any running background threads are automatically terminated. This behavior needs to be carefully considered during design to prevent data loss or corruption.

Example 

  • C#

C#

using System;
using System.Threading;

class Program
{
static void Main()
{
Thread backgroundThread = new Thread(new ThreadStart(BackgroundTask));
backgroundThread.IsBackground = true; // Set the thread to background
backgroundThread.Start();

Console.WriteLine("Main thread is completing. Background thread may not finish.");
}

static void BackgroundTask()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Background thread running...");
Thread.Sleep(1000);
}
Console.WriteLine("Background thread has completed, but this message may not display.");
}
}

Output

Main thread is completing. Background thread may not finish.


In this example, the backgroundThread is set to run as a background thread. If the main thread completes before the background thread finishes its task, the application will still terminate, and the background thread will be stopped mid-operation.

Background threads are useful for performing non-critical tasks that do not need to complete before the application terminates.

Note : It's important to note that if the main thread or all foreground threads complete while a background thread is still running, the background thread will be abruptly terminated. Therefore, you should ensure that background threads can handle sudden termination gracefully.

Frequently Asked Questions

What happens if a background thread is running when the application closes?

Background threads are terminated automatically when the main application exits. This means any ongoing processes within these threads are stopped abruptly, which can lead to incomplete tasks or data loss if not managed properly.

Can a background thread be converted to a foreground thread?

Yes, you can change a thread from background to foreground by setting its IsBackground property to false. This adjustment should be made based on the critical nature of the thread's tasks within your application.

Is it possible to prioritize one foreground thread over another?

Absolutely. In C#, you can set the Priority property of a thread to values like ThreadPriority.High, ThreadPriority.Normal, or ThreadPriority.Low. This setting helps the operating system determine how much CPU time to allocate to each thread, thus managing the execution flow based on priority.

Conclusion 

In this article, we have learned about the fundamentals of C# threads. We discussed their  properties, methods, & the differences between foreground & background threads. Threads allow us to perform multiple tasks concurrently, making our applications more efficient & responsive. 

You can refer to our guided paths on the Coding Ninjas. You can check our course to learn more about DSADBMSCompetitive ProgrammingPythonJavaJavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithmsCompetitive ProgrammingOperating SystemsComputer Networks, DBMSSystem Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.

Live masterclass