< Chapter 3 TOC: Asynchronous & Threading | Main | Controlling A Thread & Program Examples >

 


 

Chapter 3 Part 1:

Threading and the Asynchronous Pattern

 

 

What do we have in this chapter 3 Part 1?

  1. An Overview

  2. Threading

  3. Creating a Thread

  4. C++ Thread Program Example

  5. C# Thread Program Example

  6. VB .NET Thread Program Example

 

 

An Overview

 

In the previous chapter, we saw how blocking I/O is performed on different streams, including network streams. However, blocking I/O is problematic because the I/O calls might do exactly what their name implies, block for an unknown amount of time. If an application does anything besides I/O operations, such as servicing a user interface, calling a blocking method will freeze the user interface and provide for a bad user experience. You can solve this problem with the Microsoft Windows .NET Framework concurrent programming model by using threads or by using the asynchronous programming pattern.

Threads allow you to have one or more execution points in a program that can operate at the same time. When using threads, a thread can be spawned to perform any blocking I/O operations while your main application is freed to do other tasks, such as service the user interface. When a new thread is created, it begins executing from a method within your application. This method then executes all other threads in the application in parallel, including the main application thread.

The asynchronous programming pattern, on the other hand, allows many of the classes in the .NET Framework to perform operations concurrently. With the asynchronous programming pattern, you can post operations such as a read or write to be asynchronously handled by the underlying class object, and the object will signal the application when the operation has completed. This way, the application can post a number of operations concurrently, which will not block, and your main application can perform other actions such as updating the user interface and responding to user events.

This chapter introduces threads and the asynchronous pattern, which can enable you to design great networking applications. First we’ll describe the threading concept by showing how to create and manage threads to perform concurrent programming in an application where one or more threads can execute code while your main program continues to execute. Then we’ll describe thread synchronization concepts that are important to understand when using threads because of their concurrent programming behavior. Finally, after threads are described, we’ll talk about the asynchronous programming pattern that’s common to many classes in the .NET Framework and is similar in concept to the threading model.

 

Threading

 

Threading is a programming technique that permits two or more programming execution points (a place in your code) to run in an application at the same time. Threading is great because you can develop a single application that can do multiple things at the same time. For example, in Chapter 2, we described how to perform I/O over a network using synchronous programming techniques where your application could service only reading or writing data on a network and nothing else. But what if you want your application to handle several connections at the same time? Threading can help by allowing you to have multiple execution points in your code to service multiple connections in parallel. One thing to note is that you should be cautious about using too many threads to service connections, which we’ll discuss later in the chapter. Figure 3-1 demonstrates threading pictorially by describing a generic application having three threads that write data to a file, read data from a network, and update a screen.

 

An application (a process) running three threads illustration

 

Figure 3-1: An application running three threads

 

The .NET Framework provides a Thread class in the System.Threading namespace that allows you to create and manage threads in your application.

 

Creating a Thread

 

Creating a thread is simple. All you have to do is create a thread object using the System.Threading.Thread class and pass a delegate method to the Thread constructor that will be called when the thread starts running. A delegate method can be any method that does not take a parameter and does not return a value. The following code fragment demonstrates one possible way to develop a delegate method:

 

C#

 

void MyThreadMethod()

{

    // Do something useful here

}

 

Visual Basic .NET

 

Shared Sub MyThreadMethod()

   ' Do something useful here

End Sub

 

Once a delegate method is defined, you can create a thread. Creating a thread requires that you identify a delegate method to the Thread class constructor. A special class named ThreadStart allows you to define a delegate method to a thread. Once the delegate method is defined, you simply pass a ThreadStart object to the Thread constructor. The following code fragment shows how to define a ThreadStart delegate method using the MyThreadMethod() method mentioned above and create a thread:

 

C#

 

Thread MyThread = null;

try

{

    ThreadStart ThreadMethod = new ThreadStart(MyThreadMethod);

    MyThread = new Thread(ThreadMethod);

}

catch (Exception e)

{

    Console.WriteLine("Failed to create thread with error: " + e.Message);

}

 

Visual Basic .NET

 

Dim MyThread As Thread = Nothing

 

Try

Dim ThreadMethod As ThreadStart = New ThreadStart(AddressOf MyThreadMethod)

    MyThread = New Thread(ThreadMethod)

Catch e As Exception

    Console.WriteLine("Failed to create thread with error: " + e.Message)

End Try

 

Once you’ve successfully created a thread, you can begin controlling how the thread operates within your program. When the thread is created, nothing actually happens from your application’s point of view; therefore, you’re required to call the thread’s Start() method to get the thread running. Calling Start() actually tells the operating system to begin scheduling your thread for processing. The following code fragment demonstrates how to start a thread using the MyThread object created earlier:

 

C#

 

try

{

    MyThread.Start();

}

catch (Exception e)

{

    Console.WriteLine("The thread failed to start with error: " + e.Message);

}

 

Visual Basic .NET

 

Try

    MyThread.Start()

 

Catch e As Exception

    Console.WriteLine("The thread failed to start with error: " + e.Message)

End Try

 

Once the thread is started, your delegate method will begin to run. A thread can be started only once. If you try to start the thread twice, a ThreadStateException will be raised, indicating that the thread can’t be started twice. Also, when the thread delegate method completes, you can’t restart the thread; if you try to, an exception will be raised.

Your application is allowed to run only a finite number of threads at the same time. If you try to start a thread while too many threads are running, Start() will throw an OutOfMemoryException. You might be wondering how many threads can start running in your application. It depends on operating system resources such as memory. In general, it’s a bad practice to run too many threads at the same time because scheduling threads for execution takes up operating system resources such as the computer processor and memory. It’s important to realize that a computer processor can actually service only one thread at a time, and when two threads are running, the operating system is switching control from one to the other. Operating system thread scheduling gives the application the illusion that each thread is running at the same time. If the application is running on a multiprocessor machine, the operating system can truly execute multiple threads at the same time. It’s important to understand that threading does not increase the amount of computing you can do in your application, but instead, it allows you to create more dynamic applications that can interact better with multiple resources at the same time instead of just doing one thing at a time.

Take note that the .NET Framework features code access security for many of the managed classes in the .NET Framework. However, threads can’t be controlled by code access security features in the .NET Framework version 1. A control flag for threads can be accessed by using the System.Security.Permissions.SecurityPermissionFlag.ControlThread permission from the System.Security.Permissions.SecurityPermission class. However, although the control flag exists, the security permission flag does not have any effect on controlling threads from a security zone.

 

C++ Thread Program Example

 

Create a new CLR console application project and you might want to use ThreadExampleCP for the project and solution names as shown below.

 

C++ Program Example - a new CLR console application, thread

 

Add the following code.

 

// ThreadExampleCP.cpp : main project file.

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Threading;

 

public ref class ThreadExample

{

public:

 

   // The ThreadProc() method is called when the thread starts.

   // It loops ten times, writing to the console and yielding

   // the rest of its time slice each time, and then ends.

   static void ThreadProc()

   {

      for ( int i = 0; i < 10; i++ )

      {

                          Console::WriteLine("In ThreadProc(), another thread, pass #{0}",i);

         // Yield the rest of the time slice...

         Thread::Sleep(700);

      }

   }

};

 

[STAThread] // Single threaded apartment

int main(array<System::String ^> ^args)

{

   Console::WriteLine("Main thread: Start a second thread..." );

   // Create the thread, passing a ThreadStart delegate that

   // represents the ThreadExample::ThreadProc method.  For a

   // delegate representing a static method, no object is required.

   Thread^ oldThread = gcnew Thread( gcnew ThreadStart( &ThreadExample::ThreadProc ) );

 

   // Start ThreadProc().  Note that on a uniprocessor, the new

   // thread does not get any processor time until the main thread

   // is preempted or yields.  Uncomment the Thread::Sleep that

   // follows oldThread->Start() to see the difference.

   oldThread->Start();

 

   // Sleeping for main thread, so ThreadProc is running...

   // Thread::Sleep(1000);

   for ( int i = 0; i < 4; i++ )

   {

      Console::WriteLine("Main thread: Do some work, pass #{0}",  i);

      Thread::Sleep(1000);

   }

   Console::WriteLine("Main thread: Call Join(), to wait until ThreadProc() ends..." );

   // Then main thread uses the Join method to wait for the new thread to terminate.

   // If not, a race condition would occur between the two threads. If this were to happen,

   // the second thread might not be able to finish processing before the application exits.

   oldThread->Join();

   Console::WriteLine("Main thread: oldThread->Join() has returned.\nPress Enter to end program..." );

   Console::ReadLine();

    return 0;

}

 

Build and run the project. The following screenshot shows a sample output.

 

C++ thread program output example

 

C# Thread Program Example

 

Create a new empty project. You can use the project and solution name given in the following Figure if you want.

 

C# Program Example - creating a new console application

 

C# Program Example - creating a new empty project

 

Next, add a new class into the empty project. You can use the class name, ThreadExampleCS as given in the following Figure.

 

C# Program Example - adding a class into existing project in Visual Studio 2008

 

Add the following code.

 

using System;

using System.Threading;

 

// <summary>

// This is a simple sample that demonstrates how to create a thread that is

// designed to update a shared variable named m_SomeNumber. The main program prints

// the shared variable on 1 second intervals 10 times showing how the shared variable

// has been changed by the thread routine.

// </summary>

namespace ThreadExampleCS

{

    class ThreadExampleCS

    {

        // <summary>

        // The main entry point for the application.

        // </summary>

        static int m_SomeNumber = 0;

 

        [STAThread] // Single threaded apartment

        static void Main(string[ ] args)

        {

            Thread MyThread = null;

 

            try

            {

                Console.WriteLine("In Main()...");

                ThreadStart ThreadMethod = new ThreadStart(MyThreadMethod);

                Console.WriteLine("ThreadStart() is OK...");

 

                MyThread = new Thread(ThreadMethod);

                Console.WriteLine("Thread() is OK...");

            }

            catch (Exception e)

            {

                Console.WriteLine("Failed to create thread with error: " + e.Message);

                return;

            }

 

            try

            {

                MyThread.Start();

                Console.WriteLine("Starting a thread using Start() is OK...");

            }

            catch (Exception e)

            {

                Console.WriteLine("The thread failed to start with error: " + e.Message);

            }

 

            for (int i = 0; i < 10; i++)

            {

                Console.WriteLine("Pass #" + i.ToString() + " The number is " + m_SomeNumber);

                Console.WriteLine("Thread is sleeping for a while using sleep(1000)...");

                Thread.Sleep(1000);

            }

        }

 

        public static void MyThreadMethod()

        {

            try

            {

                m_SomeNumber = 59;

 

                Console.WriteLine();

                Console.WriteLine("In MyThreadMethod()...");

                for (int i = 0; i < 5; i++)

                {

                    Console.WriteLine("Thread is sleeping for a while using sleep(5000)...");

                    Thread.Sleep(1000);

                    m_SomeNumber += 5;

                }

            }

            catch (ThreadAbortException e)

            {

                Console.WriteLine("Caught thread abort exception: " + e.Message);

            }

        }

    }

}

 

Build and run the project.

 

C# Program Example - building a project menu

 

C# Program Example - running a project without debugging menu

 

The following snapshot shows the output sample.

 

C# Program Example - thread program output sample  

 

While the program is running, you may want to see the process and the threads count through the Windows Task Manager (Ctrl + Alt + Del).

 

C# Program Example - process and thread seen through Windows Task Manager

 

VB .NET thread Program Example

 

Create a new class library project. You can use the project and solution name as given in the following Figures if you want.

 

 

VB .NET Program Example - Thread class library project creation

 

Add the following code.

 

Imports System

Imports System.Threading

 

' ThreadSample is a simple sample that demonstrates how to create a thread that is

' designed to update a shared variable named m_SomeNumber. The main program prints

' the shared variable on 1 second intervals 10 times showing how the shared variable

' has been changed by the thread routine.

 

Public Class Class1

    'The main entry point for the application.

    Shared m_SomeNumber As Integer = 0

 

    Shared Sub MyThreadMethod()

        Try

            m_SomeNumber = 59

            Console.WriteLine("In MyThreadMethod() sub...")

            Dim i As Integer

            For i = 0 To 4

                Console.WriteLine("Sleep(1000)...")

                Thread.Sleep(1000)

                m_SomeNumber += 5

            Next

        Catch e As ThreadAbortException

            Console.WriteLine("Caught thread abort exception: " + e.Message)

        End Try

    End Sub

 

    Shared Sub Main()

 

        Dim MyThread As Thread = Nothing

 

        Try

            Console.WriteLine("In Main() sub...")

            Dim ThreadMethod As ThreadStart = New ThreadStart(AddressOf MyThreadMethod)

            Console.WriteLine("ThreadStart() is OK...")

            MyThread = New Thread(ThreadMethod)

            Console.WriteLine("Thread() is OK...")

        Catch e As Exception

            Console.WriteLine("Failed to create thread with error: " + e.Message)

        End Try

 

        Try

            MyThread.Start()

            Console.WriteLine("Start() is OK...")

        Catch e As Exception

            Console.WriteLine("The thread failed to start with error: " + e.Message)

        End Try

 

        Dim i As Integer

        For i = 0 To 9

            Console.WriteLine("Pass #" + i.ToString() + " The number is " + m_SomeNumber.ToString())

            Console.WriteLine("Sleep(1000)...")

            Thread.Sleep(1000)

        Next

    End Sub

End Class

 

Change the Application type: to Console Application and Startup object: to Sub Main through the project Properties.

 

VB .NET Program Example - invoking the Properties page

 

VB .NET Program Example - Changing the application type from DLL to exe

 

VB .NET Program Example - setting up the Startup object to Main subroutine

 

VB .NET Program Example - Changing the project type post coding

 

Build and run the project. The following is a sample output.

 

VB .NET Program Example - Thread program output sample

 

 

 


 

< Chapter 3 TOC: Asynchronous & Threading | Main | Controlling A Thread & Program Examples >