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

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

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

Module 14 (Optional): Threading and Asynchronous Programming

13

 

 

 

Background and Foreground Threads

A managed thread runs as a background thread or a foreground thread. Background threads are identical to foreground threads except that a background thread does not keep the managed execution environment alive.

After all foreground threads have been stopped in a managed process (where the .exe file is a managed assembly), the system stops all background threads and shuts down. You can designate a thread as a background or foreground thread by setting the Thread.IsBackground property.

For example, to designate a thread as a background thread, you set Thread.IsBackground to true. Likewise, to designate a thread as foreground thread, set IsBackground to false.

All threads that enter the managed execution environment from unmanaged code are marked as background threads. All threads that are generated by creating and starting a new Thread object are foreground threads. If you create a thread that you want to listen for some activity, such as a socket connection, you should set Thread.IsBackground to true, so that your process can terminate.

For example, to set a thread t to be a background thread:

t.IsBackground = true;

14

Module 14 (Optional): Threading and Asynchronous Programming

Encapsulating thread parameters in an object

It is sometimes important to supply parameters to a thread. However, the ThreadStart delegate takes as its only parameter a ThreadStart delegate. The following code demonstrates how to use an object to encapsulate thread parameters:

using System;

using System.Threading;

class MyClassWithThreadState

{

int sleepTime;

public MyClassWithThreadState(int sleepTime)

{

this.sleepTime = sleepTime;

}

public void ThreadMethod()

{

// method can reference sleepTime Thread.Sleep(sleepTime);

}

}

class Class1

{

static void Main()

{

int sleepTime = 1000; // time for the thread to sleep MyClassWithThreadState myClassWithThreadState =

new MyClassWithThreadState(sleepTime); Thread ts = new Thread(new

ThreadStart(myClassWithThreadState.ThreadMethod));

ts.Start(); // …

}

}

Module 14 (Optional): Threading and Asynchronous Programming

15

 

 

 

Managing Threads

Topic Objective

To describe the classes that the runtime uses to pause, resume, and force threads to wait.

Lead-in

Let’s look at how the runtime provides classes to manage threads.

! Thread.Sleep causes the current thread to block

Thread.Sleep(3000); // blocks for 3 seconds Thread.Sleep(3000); // blocks for 3 seconds

!Suspend and Resume methods are not generally useful

#Can result in serious application problems like deadlocks

!Thread.Join waits for another thread to stop

t.Start();

t.Start();

t.Join(); // Wait for the thread to exit t.Join(); // Wait for the thread to exit

! Thread.WaitHandle methods wait for one or more events

WaitHandle.WaitAll(waitEvents);

WaitHandle.WaitAll(waitEvents);

! Thread.ThreadState property - bit mask of the thread's state

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

Typically, thread management includes tasks such as suspending a thread for a period of time, waiting until another thread completes, or waiting until one or more specific events occur.

Pausing and Resuming Threads

After starting a thread, you sometimes need to pause that thread for a fixed period of time. Calling Thread.Sleep causes the current thread to immediately block for the number of milliseconds you pass to Sleep, yielding the remainder of its time slice to another thread. One thread cannot call Sleep on another thread. For example, to cause the current thread to suspend for three seconds, call the static method of Thread.Sleep as follows:

Thread.Sleep(3000);

Calling Thread.Sleep(Timeout.Infinite) causes a thread to sleep until it is interrupted by another thread that calls Thread.Interrupt or is aborted by

Thread.Abort.

Using Thread.Suspend to pause a thread

You can also pause a thread by calling Thread.Suspend. When a thread calls Thread.Suspend on itself, the call blocks until the thread is resumed by another thread.

When one thread calls Thread.Suspend on another thread, the call is a nonblocking call that causes the other thread to pause. Calling Thread.Resume breaks another thread out of the suspended state and causes the thread to resume execution, regardless of how many times Thread.Suspend was called. For example, if you call Thread.Suspend five consecutive times and then call Thread.Resume, the thread resumes execution immediately following the call to Resume.

16

Module 14 (Optional): Threading and Asynchronous Programming

Unlike Thread.Sleep, Thread.Suspend does not cause a thread to immediately stop execution. The runtime must wait until the thread has reached a safe point before it can suspend the thread. A thread cannot be suspended if it has not been started or if it has stopped.

For more information about safe points, see the .NET Framework SDK.

The Suspend and Resume methods are not generally useful for applications, and you should not confuse them with synchronization mechanisms. Because Suspend and Resume do not rely on the cooperation of the thread that is being controlled, they are highly intrusive and can cause serious application problems. For example, if you suspend a thread that holds a resource needed by another thread, this causes a deadlock condition.

Some applications do need to control the priority of threads for better performance. To do this, you should use Thread.Priority rather than Thread.Suspend in your application.

Using Thread.Join to pause a thread

You can force a thread to wait for another thread to stop by calling Thread.Join, as shown in the following code:

using System;

using System.Threading;

class MyApp {//…

static void MyThreadMethod()

{

//…

}

static void Main()

{

//create, start and join a simple background thread

//MyThreadMethod is the secondary thread's entry point. Thread t = new Thread(new ThreadStart(MyThreadMethod));

//Start the thread

t.Start();

// Wait for the thread to exit t.Join();

}

}

Module 14 (Optional): Threading and Asynchronous Programming

17

 

 

 

Using the WaitHandle class to wait for events

You can force a thread to wait for one or more events to occur by calling methods in the Thread.WaitHandle class.

The following table describes some of the methods in the WaitHandle class.

Method

Description

WaitAll

This method waits for all of the elements in the specified array to

 

receive a signal.

WaitAny

This method waits for any of the elements in the specified array to

 

receive a signal.

WaitOne

This method blocks the current thread until the current WaitHandle

 

receives a signal.

The WaitHandle class encapsulates Win32 synchronization handles. While WaitHandle objects represent operating system synchronization objects and expose advanced functionality, they are less portable than the Monitor.Wait method, which is fully managed and, in some circumstances, is more efficient in its use of operating system resources.

Using Classes that are derived from WaitHandle

Examples of classes that derive from WaitHandle include AutoResetEvent,

ManualResetEvent, and Mutex. You use the AutoResetEvent class to make a thread wait until some event puts it in the signaled state by calling

AutoResetEvent.Set. Unlike ManualResetEvent, AutoResetEvent is automatically reset to nonsignaled by the system after a single waiting thread has been released. If no threads are waiting, the event object’s state remains signaled. The AutoResetEvent corresponds to a Win32 CreateEvent call, false specified by the bManualReset argument.

18

Module 14 (Optional): Threading and Asynchronous Programming

For example, the following code shows how to force the main thread to wait until the threads that it has created signal that they have finished executing:

using System;

using System.Threading;

class MyClassWithThreadState

{

AutoResetEvent done;

public MyClassWithThreadState(AutoResetEvent done)

{

this.done = done;

}

public void ThreadMethod()

{

//…

done.Set(); // signal that we are finished

}

}

class MyApp

{

//…

static void Main()

{

//…

int numberOfThreads = 3; // number of threads to create AutoResetEvent[] waitEvents = new

AutoResetEvent[numberOfThreads]; Thread ts;

MyClassWithThreadState myClassWithThreadState; for (int i=0; i<numberOfThreads; i++)

{

waitEvents[i] = new AutoResetEvent(false); myClassWithThreadState = new

MyClassWithThreadState(waitEvents[i]); ts = new

Thread( new ThreadStart(myClassWithThreadState.ThreadMethod));

ts.Start();

}

// Wait for all threads to indicate that they are done. WaitHandle.WaitAll(waitEvents);

//…

}

}

Note You can also use multiple calls to the Thread.Join method to wait for multiple threads to exit.

In this module, thread safety describes how to force a thread to wait for access to a synchronized object, such as a Mutex method call.

Also in this module, Terminating Threads describes how to interrupt a waiting thread by calling the Thread.Interrupt or Thread.Abort method.

Module 14 (Optional): Threading and Asynchronous Programming

19

 

 

 

Thread Activity States

The Thread.ThreadState property provides a bit mask that indicates a thread’s current state. A thread is always in at least one of the possible states in the ThreadState enumeration, and can be in multiple states at the same time.

When you create a managed thread, it is in the Unstarted state, and remains in this state until it is moved into the started state by calling Thread.Start. Unmanaged threads that enter the managed environment are already in the started state.

When in the started state, some actions can cause the thread to change states. The following table lists the actions that cause a change of state and the corresponding new state.

Action

ThreadState

 

 

A thread is created within the common language runtime.

Unstarted

A thread calls Start.

Running

The thread starts running.

Running

The thread calls Sleep.

WaitSleepJoin

The thread calls Wait on another object.

WaitSleepJoin

The thread calls Join on another thread.

WaitSleepJoin

Another thread calls Interrupt.

Running

Another thread calls Suspend.

SuspendRequested

The thread responds to a Suspend request.

Suspended

Another thread calls Resume.

Running

Another thread calls Abort.

AbortRequested

The thread responds to an Abort request.

Stopped

A thread is terminated.

Stopped

Because the Running state has a value of 0, you cannot perform a bit test to discover this state. Instead, you can use the following test (in pseudo-code):

if ((tState & (Unstarted | Stopped)) == 0) // implies Running

Threads are often in more than one state at any particular time. For example, if a thread is blocked from a Wait call and another thread calls Abort on that same thread, the thread is in both the WaitSleepJoin and the AbortRequested state at the same time. In that case, as soon as the thread returns from the call to Wait or is interrupted, it receives the ThreadAbortException.

After a thread leaves the Unstarted state as the result of a call to Thread.Start, it can never return to the Unstarted state. A thread can never leave the Stopped state, either.

20

Module 14 (Optional): Threading and Asynchronous Programming

Thread Local Storage

Topic Objective

To show how to use managed thread local storage.

Lead-in

Let’s discuss how to manage thread local storage.

!Managed thread local storage - data unique to a thread

!Thread-Relative Static Fields

#Constructor code runs only on first thread, other thread’s thread static variables are initialized to null

class AClassWithThreadState class AClassWithThreadState

{{

[ThreadStatic] public static int count = 42; [ThreadStatic] public static int count = 42;

public void ThreadMethod() { public void ThreadMethod() {

count++;

}}

}}

count++;

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

Managed thread local storage (TLS) provides dynamic data slots that are unique to a thread and an application domain combination. The two types of data slots are named slots and unnamed slots. Named slots can be convenient, because you can use a mnemonic identifier. But other components can intentionally or unintentionally modify a named slot by using the same name for the component’s own thread-relative storage. However, if you do not expose an unnamed data slot to other code, it cannot be used by any other component.

To use managed TLS, create your data slot by using

Thread.AllocateNamedDataSlot or Thread.AllocateDataSlot, and use the appropriate methods to set or retrieve the information that is placed there.

Module 14 (Optional): Threading and Asynchronous Programming

21

 

 

 

Thread-Relative Static Fields

If you know that a field of your type should always be unique to a thread and application domain combination, decorate a static field with the ThreadStaticAttribute attribute. Any class constructor code runs on the first thread in the first context that accesses the field. In all other threads or contexts, the field is initialized to null, or Nothing in Microsoft Visual Basic®. Therefore, you should not rely on class constructors to initialize thread-relative static fields. Instead, you should always assume that thread-relative static fields are initialized to null.

For example, the following code shows how to use thread relative static fields to store a thread specific counter:

class AClassWithThreadState

{

//NOTE: Only the first thread instance's field is

//initialized, other threads have the field zeroed [ThreadStatic] public static int count = 42;

public void ThreadMethod()

{

count++; // …

}

//…

}

22

Module 14 (Optional): Threading and Asynchronous Programming

Demonstration: Managing Threads

Topic Objective

To demonstrate how to create and manage threads in the .NET Framework.

Lead-in

In this demonstration, you will see how to create and manage threads in .NET, by using some of the classes and methods that we have talked about in this section.

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

Delivery Tip

You should run this demo with breakpoints set in the

Main, MyThreadMethod, and

MyClassWithThreadState. ThreadMethod methods and observe the

Visual Studio .NET

Threads window.

To make the Visual Studio

.NET Threads window visible, when the application is running, on the Debug menu, click Windows, and then click Threads.

This demonstration shows first how to create, manage, and join with a simple background thread. Then a more complex example is shown where parameters and thread static values for a thread instance are encapsulated in a class, MyClassWithThreadState. After starting multiple threads, the main thread calls the WaitHandle.WaitAll method to wait until all those threads indicate that they have finished executing by setting their AutoResetEvent objects.

The code for this demonstration is located in <install folder>\Democode\ Mod14\Demo14.1.

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