C sharp - Threading in C# – Working with Multiple Threads

Threading in C# – Working with Multiple Threads

1. What is a Thread?

  • A thread is the smallest unit of execution in a program.

  • By default, every C# program starts with one thread (the main thread).

  • Threading allows you to do multiple tasks at the same time (concurrency).

Example:

  • Main thread is running the UI.

  • Another thread downloads data in the background.

  • Another thread processes that data.


2. Creating Threads

C# provides several ways to create and manage threads.

a) Using Thread class

using System;
using System.Threading;

class Program
{
    static void PrintNumbers()
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine($"Number: {i}");
            Thread.Sleep(500); // pause for half a second
        }
    }

    static void Main()
    {
        Thread t1 = new Thread(PrintNumbers); // create new thread
        t1.Start(); // run method in separate thread

        Console.WriteLine("Main thread continues...");
    }
}
  • Here, PrintNumbers runs on a separate thread, while the main thread keeps going.


b) Using Lambda Expression

Thread t2 = new Thread(() =>
{
    Console.WriteLine("Thread running with lambda expression.");
});
t2.Start();

c) Using ThreadPool

  • Instead of creating threads manually, use the ThreadPool for lightweight, short-lived tasks.

ThreadPool.QueueUserWorkItem(state =>
{
    Console.WriteLine("Thread from ThreadPool.");
});

3. Thread Synchronization

When multiple threads work on shared data, you must prevent conflicts.

Problem: Race Condition

int counter = 0;

void Increment()
{
    for (int i = 0; i < 1000; i++)
    {
        counter++; // multiple threads may corrupt this
    }
}

Solution: lock keyword

object lockObj = new object();
int counter = 0;

void Increment()
{
    for (int i = 0; i < 1000; i++)
    {
        lock (lockObj)
        {
            counter++;
        }
    }
}
  • lock ensures only one thread enters that block at a time.


4. Foreground vs Background Threads

  • Foreground threads: Keep running until they finish, even if the main program ends.

  • Background threads: Stop automatically when the main program ends.

Thread t = new Thread(PrintNumbers);
t.IsBackground = true; // runs as background thread
t.Start();

5. Modern Alternative: Tasks

In modern C#, instead of raw Thread, we often use Task and async/await (built on top of threading).

using System.Threading.Tasks;

await Task.Run(() =>
{
    Console.WriteLine("Running task in background.");
});

6. Best Practices

  • Prefer Tasks and async/await over raw Thread for most cases.

  • Use lock, Monitor, or Mutex to avoid race conditions.

  • Don’t create too many threads manually — use ThreadPool or Task for efficiency.