Home C# Tutorial on Thread Life Cycle in C#

Tutorial on Thread Life Cycle in C#

In C#, a thread’s life cycle refers to the different states a thread goes through from its creation to its termination.

Understanding the thread life cycle is essential for managing thread behavior, synchronization, and handling different scenarios in multithreaded applications.

In this tutorial, we’ll cover:

1. Thread Life Cycle States

A thread in C# goes through several states during its life cycle. Here are the main states:

  • Unstarted: The thread is created but has not started executing.
  • Running: The thread is actively executing code.
  • WaitSleepJoin: The thread is blocked, either waiting for another thread to complete (Join), sleeping (Sleep), or waiting on a synchronization object.
  • Suspended (not used often, deprecated): The thread is temporarily paused.
  • Stopped: The thread has finished executing.

2. Creating and Starting a Thread

The Thread class in C# is part of the System.Threading namespace. To create a thread, you define its behavior in a method and then create a Thread object, passing the method as a parameter. A thread begins in the Unstarted state and transitions to Running once started.

using System;
using System.Threading;

class Program {
    static void Main() {
        // Create a thread
        Thread thread = new Thread(() => {
            Console.WriteLine("Thread is running...");
            Thread.Sleep(1000); // Simulate work
        });

        Console.WriteLine("Thread State before starting: " + thread.ThreadState); // Unstarted

        // Start the thread
        thread.Start();
        Console.WriteLine("Thread State after starting: " + thread.ThreadState); // Running
    }
}

Output:

Thread State before starting: Unstarted
Thread is running...
Thread State after starting: Running

In this example:

  • The thread starts in the Unstarted state.
  • Once Start() is called, it transitions to the Running state.

3. Thread States with Examples

Unstarted to Running

When a thread is created, it remains in the Unstarted state until Start() is called.

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread = new Thread(() => {
            Console.WriteLine("Thread has started executing.");
        });

        Console.WriteLine("Thread State: " + thread.ThreadState); // Unstarted
        thread.Start();
        Console.WriteLine("Thread State after Start: " + thread.ThreadState); // Running
    }
}

Output:

Thread State: Unstarted
Thread State after Start: Running
Thread has started executing.

Running to WaitSleepJoin

When a thread calls Thread.Sleep or Join (to wait for another thread), it enters the WaitSleepJoin state.

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread = new Thread(() => {
            Console.WriteLine("Thread started. Going to sleep for 2 seconds...");
            Thread.Sleep(2000); // Enter WaitSleepJoin state
            Console.WriteLine("Thread woke up from sleep.");
        });

        thread.Start();
        Thread.Sleep(500); // Give the thread time to reach sleep state
        Console.WriteLine("Thread State during sleep: " + thread.ThreadState); // WaitSleepJoin
    }
}

Output:

Thread started. Going to sleep for 2 seconds...
Thread State during sleep: WaitSleepJoin
Thread woke up from sleep.

In this example:

  • The thread goes to sleep, transitioning to the WaitSleepJoin state.

Running to Stopped

Once a thread has finished executing its code, it moves to the Stopped state.

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread = new Thread(() => {
            Console.WriteLine("Thread is executing...");
        });

        thread.Start();
        thread.Join(); // Wait until the thread finishes
        Console.WriteLine("Thread State after completion: " + thread.ThreadState); // Stopped
    }
}

Output:

Thread is executing...
Thread State after completion: Stopped

In this example:

  • thread.Join() waits for the thread to finish, after which its state becomes Stopped.

4. Checking a Thread’s State

You can check a thread’s state at any point using the ThreadState property. This is particularly useful to verify if a thread is still running, waiting, or has completed.

Example: Using ThreadState to Monitor a Thread’s Status

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread = new Thread(() => {
            Console.WriteLine("Thread is running...");
            Thread.Sleep(1000); // Simulate work
        });

        Console.WriteLine("Initial State: " + thread.ThreadState); // Unstarted
        thread.Start();

        // Check thread state periodically
        while (thread.IsAlive) {
            Console.WriteLine("Thread State: " + thread.ThreadState); // Running or WaitSleepJoin
            Thread.Sleep(200); // Poll every 200 ms
        }

        Console.WriteLine("Final State: " + thread.ThreadState); // Stopped
    }
}

Output:

Initial State: Unstarted
Thread is running...
Thread State: Running
Thread State: WaitSleepJoin
Final State: Stopped

In this example:

  • The ThreadState property is used to monitor the thread’s status in real time.

5. Practical Examples of Thread State Transitions

Example 1: Coordinating Two Threads

In this example, one thread waits for another to finish before starting its own work.

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread1 = new Thread(() => {
            Console.WriteLine("Thread 1 started.");
            Thread.Sleep(1500);
            Console.WriteLine("Thread 1 completed.");
        });

        Thread thread2 = new Thread(() => {
            Console.WriteLine("Waiting for Thread 1 to complete...");
            thread1.Join();
            Console.WriteLine("Thread 2 started after Thread 1 completed.");
        });

        thread1.Start();
        thread2.Start();
    }
}

Output:

Thread 1 started.
Waiting for Thread 1 to complete...
# Thread 1 completes after 1.5 seconds
Thread 1 completed.
Thread 2 started after Thread 1 completed.

In this example:

  • thread2 uses Join to wait for thread1 to finish before starting its own work.

Example 2: Waiting for Multiple Threads to Complete

In scenarios where multiple threads are executing tasks, you can use Join to ensure that all threads have completed before proceeding.

using System;
using System.Threading;

class Program {
    static void Main() {
        Thread thread1 = new Thread(() => {
            Console.WriteLine("Worker 1 started.");
            Thread.Sleep(1000);
            Console.WriteLine("Worker 1 completed.");
        });

        Thread thread2 = new Thread(() => {
            Console.WriteLine("Worker 2 started.");
            Thread.Sleep(2000);
            Console.WriteLine("Worker 2 completed.");
        });

        Thread thread3 = new Thread(() => {
            Console.WriteLine("Worker 3 started.");
            Thread.Sleep(1500);
            Console.WriteLine("Worker 3 completed.");
        });

        thread1.Start();
        thread2.Start();
        thread3.Start();

        Console.WriteLine("Waiting for all workers to complete...");

        thread1.Join();
        thread2.Join();
        thread3.Join();

        Console.WriteLine("All workers have completed.");
    }
}

Output:

Worker 1 started.
Worker 2 started.
Worker 3 started.
Waiting for all workers to complete...
# Each thread completes in the order of its sleep time
Worker 1 completed.
Worker 3 completed.
Worker 2 completed.
All workers have completed.

In this example:

  • The main thread waits for all worker threads to complete by calling Join on each.

Summary

In this tutorial, we covered the different states in a thread’s life cycle and demonstrated how to manage and monitor thread states in C#.

Here’s a quick recap:

  1. Thread Life Cycle States: Overview of Unstarted, Running, WaitSleepJoin, and Stopped states.
  2. Creating and Starting a Thread: Starting a thread and understanding the transition from Unstarted to Running.
  3. Thread States with Examples: Demonstrating transitions between states like Running, WaitSleepJoin, and Stopped.
  4. Checking a Thread’s State: Using ThreadState to monitor a thread’s progress.
  5. Practical Examples of Thread State Transitions:
    • Coordinating threads using Join.
    • Waiting for multiple threads to complete.

Understanding thread life cycles and managing thread states can help you build robust and efficient multithreaded applications in C#.

You may also like