Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#

.pdf
Скачиваний:
194
Добавлен:
12.02.2016
Размер:
16.87 Mб
Скачать

Module 14 (Optional): Threading and Asynchronous Programming

93

 

 

 

Scenario

In this scenario, you use a Windows Forms client to invoke methods on a logger server that writes messages to a log file. When starting the logger server the client specifies the filename to use as a log file. After the logger server starts, it opens the log file and begins two concurrent operations. In the first operation, the server periodically writes the date and time to the log file; the server does this by using a System.Thread.Timer object that uses a thread from the thread pool.

In the second operation, the server periodically updates the client’s progress bar to indicate to the user that the logger service is running. The server does this by creating and starting a background thread. When the user stops the logger server, the server terminates both concurrent operations and closes the log file.

While the logger server is running, the client can invoke a synchronous or an asynchronous write of a text string to the log file. The asynchronous write is done according to the .NET Framework asynchronous design pattern. The client starts the asynchronous write by calling the BeginInvoke method of a delegate to the logger server’s write method. The client, as a parameter to this call, supplies an AsyncCallback delegate object that refers to the client’s method that is called when the write operation completes.

Because multiple client calls to the server can execute concurrently, the server’s methods must be implemented in a thread-safe manner.

Estimated time to complete this lab: 50 minutes

94

Module 14 (Optional): Threading and Asynchronous Programming

Exercise 1

Creating Thread-safe Methods

In this exercise, you will add thread-safe code to the MyLogger static methods to start the logger, stop the logger, and write to the log file.

!Implement the StartLogger method

1.In Visual Studio .NET, open the Multithreading project which is located in <install folder>\Labs\Lab14\Starter.

2.Open the file Form1.cs and locate the following comment for the

StartLogger method of the MyLogger class:

// TODO - Exercise 1.1: Add code to start logger

Note You can use the Visual Studio .NET Task List window to quickly locate this code. To display this window, on the View menu, click Show Tasks, and click All.

3.Use a lock statement to ensure that only one thread at a time executes the method’s code.

Because StartLogger is a static method, you lock on the System.Type object of the MyLogger class. You can obtain this object by using the following expression:

typeof(MyLogger)

Place the remainder of the StartLogger method’s code within the lock statement block.

4.Create a conditional expression that evaluates whether the logger is running. If the logger is running, throw an InvalidOperationException exception. If the logger is not running (loggerRunning is false):

a.Initialize numberOfWrites to zero.

b.Create a FileStream object for the file that is specified in the filename parameter of the StartLogger method. The new FileStream object also takes the filename, FileMode.OpenOrCreate and FileAccess.Write parameters.

c.Create a StreamWriter object and pass in the new FileStream object. This new object should be assigned to the existing static member variable w.

d.Set the file pointer to the end of the new stream by calling the StreamWriter object’s seek method as follows:

w.BaseStream.Seek(0, SeekOrigin.End);

e.Write to the stream by using the following format and supplying the current time and date as the parameters:

"\nStartLogger – Time: {0} {1} \n\n"

Module 14 (Optional): Threading and Asynchronous Programming

95

 

 

 

f.Flush the stream.

g.Set the existing static member variable form to the value of the parameter aForm in the StartLogger method.

h.Set the existing static member variable mi to a new delegate object of type MethodInvoker that refers to the form object’s UpdateProgress method.

i.Set loggerRunning to true.

! Implement the StopLogger method

1.In Form1.cs, locate the following comment for the StopLogger method of the MyLogger class:

// TODO - Exercise 1.2: Add code to stop logger

2.Use a lock statement to ensure that only one thread at a time executes the static method’s code.

Place the remainder of the StopLogger method’s code within the lock statement block.

3.Create a conditional expression that evaluates whether the logger is running. If the logger is not running, throw an InvalidOperationException exception. If the logger is running (loggerRunning is true):

a. Write to the stream by using the following format and supplying the current time and date as the parameters:

"\nStopLogger – Time: {0} {1} \n\n"

b.Close the stream.

c.Set loggerRunning to false.

96Module 14 (Optional): Threading and Asynchronous Programming

!Implement the WriteLog method

1.In Form1.cs, locate the following comment for the WriteLog method of the

MyLogger class:

//TODO - Exercise 1.3: Add code to write to logger

2.Use a lock statement to ensure that only one thread at a time executes the static method’s code.

Place the remainder of the WriteLog method’s code within the lock statement block.

3.Create a variable of type int that is named writeCount and initialize it to the value of numberOfWrites.

4.Create a conditional expression that evaluates whether the logger is running. If the logger is not running, throw an InvalidOperationException exception. If the logger is running (loggerRunning is true):

a.Make the thread sleep for 2 seconds.

b.Increment the value of writeCount by 1.

c.Write to the stream by using the following format and supplying writeCount and logText as the parameters:

"\nCount: {0} Text: {1} - Time:"

d. Write to the stream by using the following format and supplying the current time and date as the parameters:

"{0} {1} \n\n"

e.Flush the stream.

f.Set numberOfWrites to the value of writeCount.

5.Return writeCount.

Module 14 (Optional): Threading and Asynchronous Programming

97

 

 

 

! Test the application

1.Build and run the application by using Visual Studio .NET. Ignore warning messages about fields that are never used.

2.In the Text To Log field, type Hello World.

3.To check the error reporting, click Synchronous Write, and note the following message in the status bar at the bottom of the form:

“Invalid Operation - Write failed because logger was stopped”

4.Click Start Logger, and note the Logger State Indicator progress bar and the following message in the status bar:

“Logger started”

5.Click Synchronous Write, and note that after a pause of 2 seconds the following message is displayed in the status bar:

“Log written, count = 1”

6.Click Synchronous Write, and note that after a pause of 2 seconds the following message is displayed in the status bar:

“Log written, count = 2”

7.Click Stop Logger, and note that the message in the status bar now says: “Logger stopped”

8.Use Visual Studio .NET to view the log file Log.txt, that was created in the same folder as the multithreading application’s executable program:

<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug You should see output that is similar to the following:

StartLogger - Time: 11:09:48 AM Wednesday, September 19, 2001

Count:1 Text: Hello World - Time:11:10:40 AM Wednesday,

September 19, 2001

Count:2 Text: Hello World - Time:11:11:30 AM Wednesday,

September 19, 2001

StopLogger - Time:11:11:56 AM Wednesday, September 19, 2001

9. Stop the application and delete Log.txt.

98

Module 14 (Optional): Threading and Asynchronous Programming

Exercise 2

Periodically Writing to a Log File

In this exercise, you will add code to the MyLogger class to use a System.Thread.Timer object. This object is used to periodically write a message to the log file indicating that the logger is alive when the logger is running.

!Create the Timer object

1.In Form1.cs, locate the following comment for the StartLogger method of the MyLogger class:

// TODO - Exercise 2.1: Add code to periodically call ! a method using a System.Threading.Timer object

2.Locate the line of code that sets loggerRunning to true, and after this line assign to the static member variable timer a new object of type

System.Threading.Timer.

The new object should call the MyLogger class’s LogStatus method every 5 seconds. LogStatus is a static method whose delegate type is

TimerCallback.

!Dispose of the Timer object

1.In Form1.cs, locate the following comment for the StopLogger method of the MyLogger class:

// TODO - Exercise 2.2: Add code to dispose of the! System.Threading.Timer object

2.Locate the line of code that writes the string "\nStopLogger - Time:" to the log file and before this line add code that invokes the Dispose method on the timer object.

!Add the Timer object that writes logger alive messages periodically to the log file

1.In Form1.cs, locate the following comment for the LogStatus method of the

MyLogger class:

// TODO - Exercise 2.3: Add Timer callback method code to! write the date and time to the log

2.Write to the stream the following string:

"\nLogger Alive: "

3.Once again, write to the stream by using the following format and supplying the current time and date as the parameters:

"{0} {1} \n\n"

Module 14 (Optional): Threading and Asynchronous Programming

99

 

 

 

! Test the application

1.Build and run the application by using Visual Studio .NET. Ignore warning messages about fields that are never used. Ensure that you have deleted the file Log.txt that was created in the preceding exercise.

2.In the Text To Log field, type Hello World.

3.Click Start Logger, and note the following message in the status bar: “Logger started”

4.Click Synchronous Write, and note that after a pause of 2 seconds the following message is displayed in the status bar:

“Log written, count = 1”

5.Click Synchronous Write, and note that after a pause of 2 seconds the message in the status bar changes to:

“Log written, count = 2”

6.Click the Stop Logger button and note that the message in the status bar now says;

“Logger stopped”

7.Use Visual Studio .NET to view the file Log.txt that was created in the same folder as the multithreading application’s executable program:

<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug You should see output that is similar to the following:

StartLogger - Time: 11:47:21 AM Wednesday, September 19, 2001

Logger Alive: 11:47:21 AM Wednesday, September 19, 2001

Count:1 Text: Hello World - Time:11:47:24 AM Wednesday,

September 19, 2001

Logger Alive: 11:47:26 AM Wednesday, September 19, 2001

Count:2 Text: Hello World - Time:11:47:27 AM Wednesday,

September 19, 2001

StopLogger - Time:11:47:28 AM Wednesday, September 19, 2001

8. Stop the application and delete Log.txt.

100

Module 14 (Optional): Threading and Asynchronous Programming

Exercise 3

Providing the User with Status

In this exercise, you will add code to the MyLogger class to use a background thread that periodically advances the Progress Bar in the user interface whenever the logger is running.

!Create the background thread

1.In Form1.cs, locate the following comment for the StartLogger method of the MyLogger class:

// TODO - Exercise 3.1: Add code to start a background! thread

2.Locate the line of code that assigns to the static member variable timer a new object of type System.Threading.Timer and after this line, add code to do the following steps.

3.Create a new object of type Thread

The Thread object is initialized with a delegate object of type ThreadStart that refers to the ThreadProc method of the MyLogger class. This new object should be assigned to the existing static member variable timerThread.

4.Make timerThread a background thread by using its IsBackground property.

5.Start the timerThread background thread.

!Interrupt the background thread

1.In Form1.cs, locate the following comment for the StopLogger method of the MyLogger class:

// TODO - Exercise 3.2: Add code to stop a background! thread

2.Locate the line of code that invokes the Dispose method on the timer object and before this line, set up a conditional expression that checks whether the background thread is not null. If the background thread named timerThread is not null:

a. Call the timerThread Interrupt method. b. Assign timerThread, form, and mi to null.

Module 14 (Optional): Threading and Asynchronous Programming

101

 

 

 

! Advance the form’s progress bar periodically

1.In Form1.cs, locate the following comment for the ThreadProc method of the MyLogger class:

// TODO - Exercise 3.3: Add code to update the client's! progress indicator

2.In a try/catch block’s try section, insert a while(true) statement whose block contains the following steps:

a. Call the form object’s BeginInvoke method.

Pass as the BeginInvoke method’s parameter the delegate object of type

MethodInvoker that refers to the form object’s UpdateProgress method. This object was created in the StartLogger method and is named mi.

b.Make the thread sleep for ½ second.

3.In the try/catch block’s catch section add code to do the following:

a.Catch exceptions of the type ThreadInterruptedException.

b.Within the catch block, do nothing.

This will resolve the exception and the thread will terminate gracefully.

! Test the application

1.Build and run the application by using Visual Studio .NET. Ensure that you have deleted the file Log.txt that was created in the preceding exercise.

2.In the Text To Log field, type Hello World.

3.Click Start Logger.

Note that the Logger State Indicator progress bar is advancing and note the following message in the status bar.

“Logger started”

4.Click Synchronous Write, and note that the progress bar stops advancing.

After a pause of 2 seconds, the progress bar jumps ahead and the following message is displayed in the status bar.

“Log written, count = 1”

5.Click Synchronous Write, and note that the progress bar stops advancing.

After a pause of 2 seconds, the progress bar jumps ahead and the following message is displayed in the status bar.

“Log written, count = 2”

6.Click Stop Logger.

Note that the Logger State Indicator progress bar has stopped advancing and note that the message in the status bar now says:

“Logger stopped”

102

Module 14 (Optional): Threading and Asynchronous Programming

7.Use Visual Studio .NET to view the file Log.txt that was created in the same folder as the multithreading application’s executable program:

<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug You should see output that is similar to the following:

StartLogger - Time: 11:56:44 AM Wednesday, September 19, 2001

Logger Alive: 11:56:44 AM Wednesday, September 19, 2001

Count:1 Text: Hello World - Time:11:56:47 AM Wednesday,

September 19, 2001

Logger Alive: 11:56:49 AM Wednesday, September 19, 2001

Count:2 Text: Hello World - Time:11:56:50 AM Wednesday,

September 19, 2001

StopLogger - Time:11:56:53 AM Wednesday, September 19, 2001

8. Stop the application and delete the Log.txt.

Соседние файлы в папке c#