Скачиваний:
64
Добавлен:
15.03.2015
Размер:
4.31 Mб
Скачать

Multi-Threading

CHAPTER 23

And here’s the output:

Hello from a single thread.

In Listing 23.1, an object of type SingleThread is instantiated within the Main() method. It contains the SayHello() method, which is executed as part of the thread in this program. All of the thread creation and initialization occurs in the following line:

Thread th = new Thread(new ThreadStart(st.SayHello));

The Thread object is declared as th. It’s instantiated as a new Thread object with a new ThreadStart delegate as its parameter. The delegate method handler for the

ThreadStart delegate is the SayHello() method of the SingleThread object, st.

Now the thread exists, but it’s idle, waiting for directions. It’s said to be in the unstarted state. To get this thread running, the program invokes the Start() method of the Thread object, th.

Synchronization

Using the techniques from Listing 23.1, it’s easy to create multiple threads of execution. As long as each thread minds its own business, the program runs fine. However, in many situations, this is not practical. It’s often necessary for multiple threads to share a resource. Without control, the behavior of multi-threaded programs sharing a resource yields non-deterministic results.

To provide that control, C# allocates methods to coordinate activities between threads. This coordination is properly termed synchronization. Correct implementation of synchronization enables programs to take advantage of performance benefits of multithreading as well as maintaining the integrity of object state and data.

This section uses the C# lock keyword to provide data synchronization. The code in Listing 23.2 shows how.

LISTING 23.2 Synchronized Data Access: Synchronization.cs

using System;

using System.Threading;

///<summary>

///Synchronized data.

///</summary>

class SyncData

{

int index = 0;

499

23

HREADINGT-ULTIM

500

Extreme C#

PART IV

LISTING 23.2 continued

string[] comment = new string[]

{ “one”,

“two”, “three”,

“four”, “five”,

“six”,

“seven”, “eight”,

“nine”, “ten” };

public string GetNextComment()

{

// allow only a single thread at a time lock (this)

{

if (index < comment.Length)

{

return comment[index++];

}

else

{

return “empty”;

}

}

}

}

///<summary>

///Demonstrates synchronized data access.

///</summary>

class Synchronization

{

SyncData sdat = new SyncData();

static void Main(string[] args)

{

Synchronization sync = new Synchronization();

Thread t1 = new Thread(new ThreadStart(sync.GetComments)); Thread t2 = new Thread(new ThreadStart(sync.GetComments)); Thread t3 = new Thread(new ThreadStart(sync.GetComments));

t1.Name = “Thread 1”; t2.Name = “Thread 2”; t3.Name = “Thread 3”;

t1.Start();

t2.Start();

t3.Start();

}

public void GetComments()

{

string comment;

Multi-Threading

CHAPTER 23

501

LISTING 23.2 continued

do

{

comment = sdat.GetNextComment();

Console.WriteLine(

“Current Thread: {0}, comment: {1}”, Thread.CurrentThread.Name, comment);

} while (comment != “empty”);

}

}

Here’s sample output from Listing 23.2:

Current Thread: Thread 1, comment: one

Current Thread: Thread 3, comment: two

Current Thread: Thread 2, comment: three

Current Thread: Thread 1, comment: four

Current Thread: Thread 1, comment: five

Current Thread: Thread 1, comment: six

Current Thread: Thread 1, comment: seven

Current Thread: Thread 1, comment: eight

Current Thread: Thread 1, comment: nine

Current Thread: Thread 1, comment: ten

Current Thread: Thread 1, comment: empty

Current Thread: Thread 3, comment: empty

Current Thread: Thread 2, comment: empty

There are three threads of execution in Listing 23.2 that obtain synchronized access to data. The construction of the threads in the Main() method of the Synchronization class is similar to how threads were created in Listing 23.1. To keep track of each thread, the program sets each thread’s Name property.

The GetComments() method of the Synchronization class is run by each thread. This method obtains a new piece of data, comment, from a SyncData object and prints its value to the console. The loop ends when the SyncData object returns the string empty.

The SyncData object provides synchronized access to its data. The only way to get to the data is through the public GetNextComment() method. Within this method is an if statement, keeping data reads from going beyond the bounds of the array. Until index reaches the end of the array, the next comment is returned and index is incremented so the next thread gets the next comment. When index reaches the end of the array, the method returns the string empty to signify that there is no more data to return.

23

HREADINGT-ULTIM

502

Extreme C#

PART IV

Surrounding the if statement in the GetNextComment() method is a lock statement. Here’s a cutout of the lock statement from Listing 23.2:

lock (this)

{

// statements

}

The parameter of the lock statement is this. The parameter for a lock statement can be any reference type expression. An invalid expression would be a value type, such as an int type. The lock statement implements mutual exclusion on the statements inside the curly braces.

Tip

Use the lock statement for mutually exclusive access to data in a multi-threaded program.

Without the lock statement, it would be possible for two or more threads to be reading the same value at the same time. In the absence of a lock statement, if the statements inside the curly braces represented an airline seat reservation or a bank account withdrawal, the results would not be nice. The lock statement ensures that only one thread at a time can be executing those statements.

Summary

This chapter presented multi-threaded applications in C#. The first section discussed how to create and start a thread, including declaring a thread argument and passing it a delegate with the method to be invoked, as well as executing the thread.

To keep threads from wreaking havoc with shared data, it’s often necessary to use synchronization objects. Proper thread synchronization helps manage access to program data. The example program in this chapter used lock statements, providing a mutual exclusion access scenario to program data.

Multi-threading is common on server programs that create new threads to handle client requests. The next chapter, “Browsing the Network Libraries,” shows how to create clients and servers that communicate over a network.

CHAPTER 25

String

Manipulation

IN THIS CHAPTER

The String Class 516

The StringBuilder Class 533

String Formatting

540

Regular Expressions

541