8.1 Multithreading Fundamentals

  • Multithreading allows a program to execute multiple threads simultaneously, enabling parallel execution of code paths.
  • A thread is an independent flow of execution within a process.
  • By default, a C# application runs on a single thread (Main thread).
  • Multithreading improves responsiveness, especially in UI apps and performance in multi-core processors.
  • Threads share the same process memory but have their own stack and execution context.
  • The System.Threading namespace contains classes and types for implementing multithreading.

8.2 Thread Class, Creating and Managing Threads

Creating Threads

  • Use the Thread class from System.Threading to create and control threads.
  • Thread constructor accepts a method (using ThreadStart or ParameterizedThreadStart delegates) to execute on the new thread.
  • Start a thread by calling Start() method.
  • Examples:
using System;
using System.Threading;
class ThreadExample
{
    static void PrintNumbers()
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine($"PrintNumbers: {i} (Thread {Thread.CurrentThread.ManagedThreadId})");
            Thread.Sleep(500);
        }
    }
 
    static void Main()
    {
        Thread t1 = new Thread(PrintNumbers);
        t1.Name = "WorkerThread";
        t1.Start();
        Console.WriteLine($"Main thread: {Thread.CurrentThread.ManagedThreadId}");
        t1.Join(); // Wait for thread t1 to finish
    }
}
  • To pass parameters to threads, use ParameterizedThreadStart or lambda expressions:

 
Thread t2 = new Thread(param =>
 
{
 
    Console.WriteLine("Parameter received: " + param);
 
});
 
t2.Start("Hello Thread");
 

8.3 Threads Priority and Thread Synchronization

Thread Priority

  • Threads have priority levels from ThreadPriority.Lowest to ThreadPriority.Highest.
  • Changing priority helps the scheduler decide which threads get processor time first.
  • Set priority using thread.Priority = ThreadPriority.AboveNormal;

Thread Synchronization

  • Necessary to prevent race conditions and ensure thread-safe access to shared resources.
  • Common synchronization primitives:     - lock statement (Monitor)     - Mutex     - Semaphore     - AutoResetEvent / ManualResetEvent
  • Example with lock:
class Counter
{
    private int total = 0;
    private readonly object locker = new object();
 
    public void Increment()
    {
        lock (locker)
        {
            total++;
            Console.WriteLine($"Total: {total}");
        }
    }
}

8.4 Suspending, Resuming and Terminating Threads

  • Methods like Thread.Suspend() and Thread.Resume() exist but are deprecated and can cause deadlocks.

  • Use synchronization primitives (e.g., ManualResetEvent) to coordinate thread execution.

Terminating Threads

  • Thread.Abort() is also deprecated.

  • Threads should be cooperatively cancelled using cancellation tokens or a shared flag.

Safe Alternative Example for Pause/Resume

 
class Worker
 
{
 
    private ManualResetEventSlim _pauseEvent = new ManualResetEventSlim(true);
 
    private bool _shouldStop = false;
 
  
 
    public void DoWork()
 
    {
 
        while (!_shouldStop)
 
        {
 
            _pauseEvent.Wait();
 
  
 
            Console.WriteLine("Working...");
 
            Thread.Sleep(500);
 
        }
 
        Console.WriteLine("Worker stopped.");
 
    }
 
  
 
    public void Pause() => _pauseEvent.Reset();
 
  
 
    public void Resume() => _pauseEvent.Set();
 
  
 
    public void Stop() => _shouldStop = true;
 
}
 

Summary

| Aspect | Description |

| :— | :— |

| Multithreading | Multiple threads run concurrently within a process |

| Thread Class | Used to create, start, and manage threads |

| Thread Priority | Used to influence thread scheduling priority |

| Thread Synchronization | Prevents race conditions via locks, mutexes, semaphores, events |

| Suspending/Resuming Threads | Deprecated direct methods, use synchronization mechanisms instead |

| Terminating Threads | Avoid Abort(), prefer cooperative cancellation |