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

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

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

Module 14 (Optional): Threading and Asynchronous Programming

23

 

 

 

Interrupting and Terminating Threads

Topic Objective

To explain how to terminate a thread by using the .NET Framework classes.

Lead-in

Let’s look at how to terminate a thread in the

.NET Framework.

!Thread.Interrupt method

#Wakes a thread from any wait state and causes a

ThreadInterruptedException

!Thread.Abort method to permanently terminate thread

#Wakes a thread from any wait state and causes a

ThreadAbortException

#ThreadAbortException is a special exception that can be caught by application code, but is rethrown at the end of the catch block unless ResetAbort is called

#Immediate abort not guaranteed, therefore use Thread.Join to block until thread terminates

*****************************ILLEGAL FOR NON-TRAINER USE******************************

In addition to starting, pausing, and resuming threads, the .NET Framework also provides classes for terminating threads.

Thread.Interrupt wakes a thread from any wait state and causes a

ThreadInterruptedException to be thrown in the destination thread.

Thread.Abort is used to permanently terminate a thread.

Using Thread.Interrupt

When you call Thread.Interrupt, you wake a thread from any wait state and cause a ThreadInterruptedException to be thrown in the destination thread. The thread should catch the ThreadInterruptedException and do whatever is appropriate to continue working. If the thread ignores the exception, the runtime catches the exception and stops the thread.

For example, you may want to terminate a thread in response to a user-initiated event, such as clicking a Cancel button. The Cancel button’s event handler may run in one thread (thread1), while the event to which the Cancel action applies may run in a separate thread (thread2). In your event handler, you can call the Interrupt method on the second thread, as follows:

// inside the Cancel button's event handler if ( thread2 != null)

{

thread2.Interrupt(); thread2 = null;

}

24

Module 14 (Optional): Threading and Asynchronous Programming

Using Thread.Abort

To terminate a thread permanently, you use the Thread.Abort method. When you call Abort to terminate a thread, the system wakes the thread from any wait state and throws a ThreadAbortException. The runtime executes the catch block and any finally block.

ThreadAbortException is a special exception that can be caught by application code, but is rethrown at the end of the catch block unless ResetAbort is called. Only code with the proper permissions can call ResetAbort method. ResetAbort cancels the request to abort, and prevents the ThreadAbortException from terminating the thread. If the finally blocks contain any unbounded computations, the thread’s termination may be delayed indefinitely.

Because the call to Thread.Abort does not always result in the immediate termination of a thread, you can ensure the thread’s destruction by calling the Join method on the thread after you call Abort. Join blocks the calling thread until the thread stops executing.

After a thread terminates, you cannot restart it by calling Start again. For example, if code creates a thread, lets it run, and then aborts the thread, any attempt to restart the thread causes the runtime to throw a

ThreadStateException.

Blocking Issues

If a thread makes an unmanaged call into the operating system, and the system has blocked the thread in unmanaged code, the runtime will not take control of the blocked thread for Thread.Interrupt or Thread.Abort.

In the case of Thread.Abort, the runtime marks the thread for Abort and takes control of the thread when it re-enters managed code. Where possible, you should use managed blocking rather than unmanaged blocking. The following methods are all responsive to Thread.Interrupt and Thread.Abort:

!WaitHandle

!WaitOne

!WaitAny

!WaitAll

!Monitor.Enter

!Monitor.Block

!Thread.Join

!GC.WaitForPendingFinalizers

Also, if a thread is in a single-threaded apartment, all of these managed blocking operations will correctly pump messages in the apartment while the thread is blocked.

Module 14 (Optional): Threading and Asynchronous Programming

25

 

 

 

Demonstration: Interrupt and Abort

Topic Objective

To demonstrate how to terminate threads by using the Thread.Interrupt and Thread.Abort methods.

Lead-in

In this demonstration, you will see how to use the

Thread.Interrupt and Thread.Abort methods to terminate threads.

*****************************ILLEGAL FOR NON-TRAINER USE******************************

This demonstration shows how to use Thread.Interrupt and Thread.Abort to terminate threads.

Pay careful attention to what happens in the catch and finally blocks when the Interrupt and Abort methods are called. Notice whether the thread resumes working after the method calls as indicated by the output string “Thread - still alive and working.”

26

Module 14 (Optional): Threading and Asynchronous Programming

The following code is used in the demonstration:

using System;

using System.Threading;

public class ThreadWork

{

static public bool resetAbort;

public static void DoWork()

{

try

{

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

{

Console.WriteLine( "Thread - working.");

Thread.Sleep(100);

}

}

catch(ThreadInterruptedException e)

{

Console.WriteLine(

"Thread - caught ThreadInterruptedException"); Console.WriteLine(

"Exception message: {0}", e.Message);

}

catch(ThreadAbortException e)

{

Console.WriteLine(

"Thread - caught ThreadAbortException"); Console.WriteLine(

"Exception message: {0}", e.Message);

if (resetAbort == true) Thread.ResetAbort();

}

finally

{

Console.WriteLine("Thread - finally block");

}

Console.WriteLine(

"Thread - still alive and working."); Thread.Sleep(1000);

Console.WriteLine(

"Thread - finished working.");

}

}

(Code continued on the following page.)

Module 14 (Optional): Threading and Asynchronous Programming

27

 

 

 

class ThreadAbortTest

{

public static void Main()

{

ThreadStart myThreadDelegate = new ThreadStart(ThreadWork.DoWork);

Thread myThread;

Console.WriteLine(

"Main - interrupting my thread."); myThread = new Thread(myThreadDelegate); myThread.Start();

Thread.Sleep(100);

myThread.Interrupt();

Thread.Sleep(2000);

ThreadWork.resetAbort = true; Console.WriteLine(

"Main - aborting my thread with resetAbort: {0}.", ThreadWork.resetAbort);

myThread = new Thread(myThreadDelegate); myThread.Start();

Thread.Sleep(100);

myThread.Abort();

Thread.Sleep(2000);

ThreadWork.resetAbort = false; Console.WriteLine(

"Main - aborting my thread with resetAbort: {0}.", ThreadWork.resetAbort);

myThread = new Thread(myThreadDelegate); myThread.Start();

Thread.Sleep(100);

myThread.Abort();

myThread.Join(); Console.WriteLine("Main ending.");

}

}

28

Module 14 (Optional): Threading and Asynchronous Programming

The output should be similar to the following:

Main - interrupting my thread. Thread - working.

Thread - caught ThreadInterruptedException Exception message: !

Thread has been interrupted from a waiting state. Thread - finally block

Thread - still alive and working. Thread - finished working.

Main - aborting my thread with resetAbort: True. Thread - working.

Thread - caught ThreadAbortException Exception message: Thread was being aborted. Thread - finally block

Thread - still alive and working. Thread - finished working.

Main - aborting my thread with resetAbort: False. Thread - working.

Thread - caught ThreadAbortException Exception message: Thread was being aborted. Thread - finally block

Main ending.

Module 14 (Optional): Threading and Asynchronous Programming

29

 

 

 

" Thread Safety

Topic Objective

To provide an overview of the topics that you will cover in this section.

Lead-in

In this section, we’ll look at the importance of thread safety and the mechanisms that the .NET Framework supports to provide thread safety.

!Overview of Thread Safety

!Synchronization Context

!Synchronized Code Regions

!Manual Synchronization

!Thread Safety and the .Net Framework Classes

*****************************ILLEGAL FOR NON-TRAINER USE******************************

The System.Threading namespace provides classes and interfaces that enable multithreaded programming. This namespace includes classes for synchronizing access to data to provide thread safety.

This section focuses on the issues that you may encounter from sharing data and resources between threads in multithreaded programming. The section also introduces .NET Framework synchronization strategies.

30

Module 14 (Optional): Threading and Asynchronous Programming

Overview of Thread Safety

Topic Objective

To discuss problems that result from sharing data and resources between threads, and to introduce .NET Framework synchronization strategies.

Lead-in

Let’s talk about how sharing data and resources between threads can lead to compromised thread safety.

!Common problems sharing data and resources between threads:

#Race condition – uncontrolled order of execution causing errors

#Deadlocks – threads waiting for each other so that they cannot proceed

!Best approach is to avoid sharing when possible

#Encapsulate data into instances that are not shared across requests

!The .NET Framework provides three strategies to synchronize access to instance and static methods and instance fields:

#Synchronized contexts

#Synchronized code regions

#Manual synchronization

*****************************ILLEGAL FOR NON-TRAINER USE******************************

When writing multithreaded applications, you may encounter common problems, such as race conditions and deadlock.

Race condition

Two or more threads that simultaneously access the same data can cause undesirable and unpredictable results. For example, one thread may update the contents of a structure while another thread reads the contents of the same structure. In this scenario, it is unknown what data the reading thread will receive: the old data, the newly written data, or possibly a mixture of both.

When the proper operation of a program depends on the uncontrolled order of execution of multiple threads, then a race condition exists.

Deadlock

A multithreaded application can also encounter problems with thread synchronization if multiple threads are waiting for each other to release resources. This blocking of thread execution is known as a deadlock.

For example, consider two threads that transfer money between accounts A and B. The first thread, Thread 1, is coded to do the following tasks in the following order:

!Wait for and acquire a lock on account A

!Wait for and acquire a lock on account B

!Transfer funds

!Release both locks

The second thread, Thread 2, is coded in the same way, except that it first acquires a lock on account B, then on account A.

Module 14 (Optional): Threading and Asynchronous Programming

31

 

 

 

Consider the case where Thread 1 acquires lock A, but before it can acquire lock B, Thread 2 runs and acquires lock B. In this case, both threads block while waiting for the other lock. Because both threads are blocked, neither thread releases the lock that is required by the other thread to proceed. This condition is referred to as a deadlock situation.

You can best achieve thread safety by not sharing data or resources between threads. If possible, use a design pattern that encapsulates data and resources into instances that are not shared across requests. When this is not possible you should use the .NET Framework thread synchronization classes to provide thread safety.

.NET Framework strategies for synchronization

When you need to share data, the .NET Framework provides three strategies to synchronize access to instance methods, static methods, and instance fields:

!Synchronized contexts

You can use the SynchronizationAttribute attribute to enable simple, automatic synchronization for ContextBoundObject objects.

!Synchronized code regions

You can use the MethodImplAttribute class (passing

MethodImplOptions.Synchronized), the Monitor class, or compiler support to synchronize only the code blocks that need it.

!Manual synchronization

You can use the various synchronization objects to create your own synchronization mechanisms.

The runtime provides a thread model in which classes fall into a number of categories that can be synchronized in a variety of different ways, depending on the requirements.

No Synchronization

No synchronization support is the default for objects. Any thread can access any method or field at any time.

Synchronized Context

You can use the SynchronizationAttribute on any class that is derived from ContextBoundObject to synchronize all instance methods and fields. All objects in the same context domain share the same lock. Multiple threads are allowed to access the instance methods and fields, but only a single thread is allowed at any one time. Static members are not protected from concurrent access by multiple threads.

The following table shows the support provided for fields and methods under the synchronization context category.

Synchronization context supports

Synchronization context does not support

Instance fields and instance methods

Global fields, static fields, and static methods

 

Specific code blocks

32

Module 14 (Optional): Threading and Asynchronous Programming

Synchronized Code Regions

You can use the Monitor class or a compiler keyword to synchronize blocks of code, instance methods, and static methods. In Microsoft Visual C#, the keyword is lock. You can also decorate a method with a MethodImplAttribute (passing MethodImplOptions.Synchronized), which has a similar result to using Monitor or one of the compiler keywords for a Monitor code block where the code block is the entire method.

The following table shows the support provided for fields and methods under the synchronized code regions category.

Synchronized code regions supports

Synchronized code regions does not

(only if marked)

support

 

 

Static methods, instance methods, and specific code blocks

Global fields, static fields, and instance fields

Manual Synchronization

You can use the Interlocked, Mutex, ManualResetEvent, AutoResetEvent, and ReaderWriterLock classes to acquire and release a lock to protect global, static, and instance fields and global, static, and instance methods.

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