Language: EN

csharp-threads

Threads in C#

In C#, threads are a way to achieve concurrent and parallel programming. They allow us to split 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 on the user interface. This is where threads allow us to divide the work into concurrent tasks.

A thread is the smallest unit of processing in a program. Normally, a program has at least one thread, called the main thread, which is responsible for executing instructions in a sequential order.

Create and run a Thread

In C#, a thread can be created by instantiating the Thread class and assigning it a method to execute. Then, we call the thread by invoking 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 running...");
            Thread.Sleep(1000);
        }
    }

    public static void BackgroundTask()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("Secondary thread running...");
            Thread.Sleep(1000);
        }
    }
}

The method that will run in the new thread must be of type void and should not have parameters (or parameters should be handled alternatively).

Useful Thread methods and properties

The Thread class provides several useful methods and properties:

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 preventing 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 a time.