Threads in C#

The previous example has shown a bit about threads, but we have to cover a few more details. When a Thread instance is created, a delegate to the function that the thread should run is created and passed to the constructor. Since a delegate can refer to a member function and a specific instance, there’s no need to pass anything else to the thread.

You can use the thread instance to control the priority of the thread, set the name of the thread, or perform other thread operations, so it’s necessary to save that thread instance if such operations will be performed later. A thread can get its own thread instance through the Thread.CurrentThread property.

1. Joining

After a thread has been created to perform a task, such as doing a computation-intensive calculation, it’s sometimes necessary to wait for that thread to complete. The following example illustrates this:

using System;

using System.Threading;

class ThreadSleeper {

int seconds;

private ThreadSleeper(int seconds)

{

this.seconds = seconds;

}

public void Nap()

{

Console.WriteLine(“Napping {0} seconds”, seconds);

Thread.Sleep(seconds * 1000);

}

public static Thread DoSleep(int seconds)

{

ThreadSleeper ts = new ThreadSleeper(seconds);

Thread thread = new Thread(new ThreadStart(ts.Nap));

thread.Start();

return(thread);

}

}

class Test {

public static void Main()

{

Thread thread = ThreadSleeper.DoSleep(5);

Console.WriteLine(“Waiting for thread to join”);

thread.Join();

Console.WriteLine(“Thread Joined”);

}

}

The ThreadSleeper.Nap() function simulates an operation that takes a while to perform. ThreadSleeper.DoSleep() creates an instance of a ThreadSleeper, executes the Nap() function, and then returns the thread instance to the main program. The main program then calls Join() on that thread to wait for it to complete.

Using Join() works well when waiting for a single thread, but if there’s more than one active thread, a call to Join() must be made for each, which is a bit unwieldy.

A nicer solution is to use one of the utility classes.

2. Waiting with WaitHandle

The WaitHandle abstract class provides a simple way to wait for an event to occur.[1] In addition to waiting for a single event to occur, it can be used to wait for more than one event and return when one or all of them occur. The AutoResetEvent and ManualResetEvent classes derive from WaitHandle. The AutoResetEvent will release only a single thread when the Set() function is called and will then reset. The ManualResetEvent may release many threads from a single call to Set() and must be cleared by calling Reset().

You can modify the previous example to use an AutoResetEvent to signal when an event is complete and to wait for more than one thread to complete:

using System;

using System.Threading;

class ThreadSleeper {

int seconds;

AutoResetEvent napDone = new AutoResetEvent(false);

private ThreadSleeper(int seconds)

{

this.seconds = seconds;

}

public void Nap()

{

Console.WriteLine(“Napping {0} seconds”, seconds);

Thread.Sleep(seconds * 1000);

Console.WriteLine(“{0} second nap finished”, seconds);

napDone.Set();

}

public static WaitHandle DoSleep(int seconds)

{

ThreadSleeper ts = new ThreadSleeper(seconds);

Thread thread = new Thread(new ThreadStart(ts.Nap));

thread.Start();

return(ts.napDone);

}

}

class Test {

public static void Main()

{

WaitHandle[] waits = new WaitHandle[2];

waits[0] = ThreadSleeper.DoSleep(8);

waits[1] = ThreadSleeper.DoSleep(4);

Console.WriteLine(“Waiting for threads to finish”);

WaitHandle.WaitAll(waits);

Console.WriteLine(“Threads finished”);

}

}

The output is as follows:

Waiting for threads to finish

Napping 8 seconds

Napping 4 seconds

4 second nap finished

8 second nap finished

Threads finished

Instead of returning a Thread, the DoSleep() function now returns a WaitHandle that will be set when the thread has completed. An array of WaitHandle is created and then is passed to WaitHandle.WaitAll() to wait for all the events to be set.

Source: Gunnerson Eric, Wienholt Nick (2005), A Programmer’s Introduction to C# 2.0, Apress; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *