C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#
.pdfModule 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;
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.
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++; // …
}
//…
}