In C#, threads are a way to achieve concurrent and parallel programming. They allow us to divide the execution of a program into multiple tasks that can run simultaneously.
In many cases, we need to perform tasks simultaneously, such as accessing a database while displaying an animation in the user interface. This is where threads allow us to split the work into concurrent tasks.
A thread is the smallest unit of processing in a program. Typically, a program has at least one thread, called the main thread, which is responsible for executing instructions in a sequential order.
Creating and Running a Thread
In C#, a thread can be created by instantiating the Thread
class and assigning it a method to execute. We then start the thread by calling the .Start()
method.
using System;
using System.Threading;
public class Program
{
public static void Main()
{
// Create a new thread
Thread newThread = new Thread(BackgroundTask);
newThread.Start(); // Start the thread
// Task in the main thread
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main thread is running...");
Thread.Sleep(1000);
}
}
public static void BackgroundTask()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Secondary thread is running...");
Thread.Sleep(1000);
}
}
}
The method that will be executed in the new thread must be of type void
and should not have parameters (or parameters should be handled in an alternative way).
Useful Thread Methods and Properties
The Thread
class provides several useful methods and properties:
Thread.Sleep(int milliseconds)
: Suspends the execution of the current thread for the specified number of milliseconds. Useful for making pauses.Thread.Join()
: Causes the main thread to wait for the secondary thread to complete its task before continuing. This is useful to ensure that a thread has finished before proceeding with execution.IsAlive
: Property that indicates whether the thread is running.Priority
: Allows setting the thread’s priority (Low, Normal, High), which affects the order of relative execution.
Thread newThread = new Thread(BackgroundTask);
newThread.Start();
// Wait for the new thread to finish before continuing
newThread.Join();
Console.WriteLine("Secondary thread finished. Continuing in the main thread.");
Thread Synchronization
Thread synchronization is essential to avoid issues such as race conditions or deadlocks.
Using the lock
keyword in C# allows only one thread to access a shared resource at a time, thus avoiding conflicts.
using System;
using System.Threading;
public class BankAccount
{
private decimal balance = 0;
private object lockObject = new object();
public void Deposit(decimal amount)
{
lock (lockObject)
{
balance += amount;
Console.WriteLine($"Deposit of {amount}. Current balance: {balance}");
}
}
}
public class Program
{
public static void Main()
{
BankAccount account = new BankAccount();
// Create multiple threads to simulate simultaneous deposits
Thread thread1 = new Thread(() => account.Deposit(100));
Thread thread2 = new Thread(() => account.Deposit(200));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
}
}
In this example, the lock
keyword ensures that only one thread can access the deposit operation at the same time.