Thread Basics


A thread is a logical unit of execution for a program. The use of multiple threads in an application enables the programmer to create a more pleasurable experience for the user. Before getting into the details of how to employ the use of threads, you will learn some of the more important properties and methods of the thread class. In the following sections, you will learn how to create, run, join, stop, suspend, and pause a thread.

Understanding the Key Thread Properties and Methods

The thread class has several key properties. These properties enable you to control the basic makeup of a thread class. Table 9.1 is a list of some of the more important properties.

Table 9.1. Notable Members of the Thread class

Property

Description

ApartmentState

This property indicates whether the thread runs in a single-threaded (STA) or multithreaded (MTA) apartment.

CurrentThread

This is a static read-only property that returns the currently active or running thread.

IsAlive

This property returns true if the thread has not been terminated or aborted; otherwise, it returns false.

IsBackground

This property returns true if the thread is a background thread; otherwise, it returns false.

IsThreadPoolThread

This method returns true if the thread is a member of a managed thread pool; otherwise, it returns false.

Name

This property enables the user to either get or set the name of the thread. This is a write-once field.

Priority

This property enables the user to set the priority of a thread. It can be one of the following values: ThreadPriority.Highest, THReadPriority.AboveNormal, ThreadPriority.Normal, ThreadPriority.BelowNormal, or THReadPriority.Lowest.

ThreadState

This property enables the user to get the state of the thread.


TIP

A background thread is essentially the same thing as a foreground thread, but with one exception: An active foreground thread prevents a process from closing, whereas a background thread does not. When a process terminates, it waits for all foreground threads to terminate and then issues an abort to all background threads.


TIP

Setting the name of a thread can be very useful when debugging a multithreaded application so that you can distinguish one thread from another. For example, if you issue Debug.WriteLine statements, providing the name of the thread from which the debug statement originated can be invaluable while stepping through an application.


TIP

Because this property has a Flags attribute, it can contain multiple values. To see whether a specific value is contained in this field, perform a bitwise comparison.


Table 9.2 contains a listing of ThreadState values.

Table 9.2. ThreadState Listing

State

Description

Value

Aborted

The thread has been aborted and is currently in the stopped state.

256

AbortRequested

A request to have this thread aborted has been made, but has not yet been processed.

128

Background

The thread is marked as a background thread.

4

Running

The thread is in the started state.

0

Stopped

The thread has been stopped.

16

StopRequested

This is for internal use only. A stop request has been issued to the thread.

1

Suspended

The thread is suspended.

64

SuspendRequested

A request has been made to suspend the thread.

2

Unstarted

The thread has not yet been started. The processor has not been requested to schedule the thread for execution.

8

WaitSleepJoin

The thread is being blocked as a result of a call to one of the following methods: Wait, Sleep, or Join.

32


In addition to these properties, several key methods are used to control the flow of threads. Those methods are listed here:

  • Abort This method raises a ThreadAbortException exception to cause the thread to terminate.

    TIP

    Although it is possible to catch a ThreadAbortException exception and perform some logging or other functions, it cannot be suppressed. The system will automatically raise the exception again at the end of the catch. The only way to cancel this exception is to use the Thread.ResetAbort method.


  • Interrupt This method causes a thread that is in a WaitSleepJoin state to be interrupted; otherwise, it waits for the thread to be placed in this state before interrupting it.

  • Join This method blocks the calling thread indefinitely until it terminates. This method cannot be used on a thread that is in the ThreadState.Unstarted state.

  • ResetAbort This method cancels a pending Thread.Abort command on the current thread.

  • Resume This method causes a suspended thread to resume execution.

  • Sleep This method causes the thread to be blocked for a specified period of time. A value of 0 indicates that the thread should be suspended to allow other threads to process. A value of Infinite suspends the thread indefinitely.

  • SpinWait This method causes a thread to wait n number of cycles before resuming.

  • Start This method causes a thread to be placed in the ThreadState.Running state and allows the processor to schedule it for execution. This method will not restart a thread that has been terminated.

  • Suspend This method suspends the thread from execution. It does not have any effect on a thread that is already suspended.

  • VolatileRead This method reads the latest value of a field regardless of how many processors are used. This method affects only single memory access.

  • VolatileWrite This method writes the value of a field immediately. This is done to make sure that it is not cached and is available to all processors.

Explaining the ThreadStart Delegate

A ThreadStart delegate is a wrapper around the program code that is to be executed by the thread. It is used as the only parameter passed during the creation of an instance of the Thread object. As with all delegates, it must contain the same parameters as the delegate declaration. You can create a ThreadStart delegate like this:

 ThreadStart workerThreadStart = new ThreadStart(SimpleWorkerThreadMethod); 

Creating a Thread

You can use a Thread object to create a new instance of a thread to run a portion of the code associated with a process. However, before running a thread, you must first gain an instance of a Thread. Obtaining an instance of a thread can be accomplished in two ways. The first way is by creating a new instance of the thread class and passing in the ThreadStart delegate:

 Thread workerThread = new Thread(workerThreadStart); 

The second way is to use the static property CurrentThread from the thread class:

 Thread workerThread = Thread.CurrentThread; 

Running a Thread

Running a thread is done by calling the Start method on an instance of a THRead object:

 workerThread.Start(); 

This causes the operating system to place the thread into a running state. When the thread is in a running state, the operating system can schedule it for execution.

Terminating a Thread

There are two ways that a thread can terminate. The first way is for the method that is wrapped by the ThreadStart delegate to finish its execution. This is demonstrated in the following code fragment:

 public static void SimpleWorkerThreadMethod() {   Console.WriteLine("Hello from the worker thread."); } 

In this case, the thread will terminate immediately after the call to Console.WriteLine. The second case is when a thread receives a ThreadAbortException exception. In this case, a thread will always terminate. As you can see, there is an infinite loop in the following code sample:

 public static void SimpleWorkerThreadMethod() {   for(int i=0; ; i++)   {     Console.WriteLine("Hello from the worker thread.");   } } 

Under normal circumstances, this thread would never terminate. If you were to call this method from your main thread, the program would never terminate and you would have to kill the process. However, if you were to call this method from a separate thread, you could call the Thread.Abort method, which would cause the thread to terminate by throwing a THReadAbortException exception and thereby breaking out of the loop. This is demonstrated in Listing 9.1.

Listing 9.1. Sample Thread Application
    using System;    using System.Threading;    namespace SimpleThreadSample    {      /// <summary>      /// This class demonstrates the basic use of threads.      /// </summary>      class SimpleAbortThreadClass      {        [STAThread]        static void Main(string[] args)        {          // Create the ThreadStart delegate.          Console.WriteLine("{Main Thread} Creating the thread start delegate.");          ThreadStart workerThreadStart = new ThreadStart(SimpleWorkerThreadMethod);          // Pass the ThreadStart delegate to the Thread in the Thread constructor.          Console.WriteLine("{Main Thread} Creating the worker thread.");          Thread workerThread = new Thread(workerThreadStart);          // Start the thread.          Console.WriteLine("{Main Thread} Starting the worker thread.");          workerThread.Start();          Console.ReadLine();          workerThread.Abort();          Console.WriteLine("{Main Thread} Aborting worker thread.");          workerThread.Join();          Console.WriteLine("{Main Thread} Worker Thread Terminated.");          Console.ReadLine();        }        public static void SimpleWorkerThreadMethod()        {          for(int i=0; ; i++)          {            try            {              Console.WriteLine("Hello from the worker thread.");            }        catch(Exception e)            {              Console.WriteLine(e.ToString() + " Exception caught.");            }          }        }      }    } 

Notice that in the SimpleWorkerThreadMethod method, the inside of the infinite loop is wrapped in an exception handler that catches all exceptions. This would typically catch any exception that occurs and suppress this error. But because the ThreadAbortException exception is a special case that cannot be suppressed, the exception is automatically rethrown after the exception handler. This causes the thread to terminate. The only way that this exception can be suppressed is to catch it and then call the Thread.AbortReset method. This is demonstrated by the following code sample:

     public static void SimpleWorkerThreadMethod()     {       for(int i=0; ; i++)       {         try         {           Console.WriteLine("Hello from the worker thread.");         }         catch(Exception e)         {           Console.WriteLine(e.ToString() + " Exception caught.");           Thread.AbortReset();         }       }     }   } } 

Suspending a Thread

When a thread is suspended, it is no longer scheduled by the processor for execution. It is simply waiting to be reawakened by some outside force. A thread can be suspended by simply calling the Thread.Suspend method.

 workerThread.Suspend(); 

When the Thread.Suspend method is called, the thread is suspended and no longer executing. To cause the thread to continue again, the Thread.Resume method must be called:

 workerThread.Resume(); 

Creating a Pause by "Sleeping" a Thread

When a thread is sleeping, it is simply blocked from execution for a specified period of time and is said to be in a WaitSleepJoin state. The WaitSleepJoin state will be explained in further detail in the next section. To place a thread in a sleeping state, simply call the Thread.Sleep method and pass the time for the thread to sleep, in milliseconds, to the method as its only parameter:

 workerThread.Sleep(1000); 

Passing in a 0 as the timeout causes the thread to be suspended, which allows other threads time to execute. Passing the keyword Infinite causes the thread to be blocked indefinitely. After the specified period of time, the thread is released and processing continues.

Joining a Thread

Calling the Thread.Join method causes the calling thread to enter the WaitSleepJoin state and to be blocked until the thread instance (shown in the example that follows as workerThread) is terminated. If the thread does not terminate, the calling thread will be blocked indefinitely. To join a thread, simply call the Thread.Join method:

 workerThread.Join(); 

This method should be used when it is necessary to wait for a thread to terminate before continuing to process . Listing 9.2 demonstrates waiting for a thread to terminate before allowing the program to finish:

Listing 9.2. A Simple Thread Class
    using System;    using System.Threading;    namespace SimpleThreadSample    {      /// <summary>      // This class demonstrates the basic use of threads.      /// </summary>      class SimpleThreadClass      {         [STAThread]        static void Main(string[] args)        {          // Create the ThreadStart delegate.          Console.WriteLine("{Main Thread} Creating the thread start delegate.");          ThreadStart workerThreadStart = new ThreadStart(SimpleWorkerThreadMethod);          // Pass the ThreadStart delegate to the Thread in the Thread constructor.          Console.WriteLine("{Main Thread} Creating the worker thread.");          Thread workerThread = new Thread(workerThreadStart);      // Start the thread.          Console.WriteLine("{Main Thread} Starting the worker thread.");          workerThread.Start();          workerThread.Join();        }        public static void SimpleWorkerThreadMethod()        {          Console.WriteLine("Hello from the worker thread.");        }      }    } 



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net