Добавил:
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

63

 

 

 

The ReadWriteLock test

The ReadWriteLock test uses an instance of the

CounterUsingReaderWriterLock class, which uses the ReaderWriterLock class to synchronize access to the object. Note that multiple readers or a single writer can execute concurrently. The five Write method calls now increment count by 5, and all of the Read operations have a consistent value for count. Because a thread that is executing a Read does not block other threads that are executing a Read, this technique enables the Read operations to complete sooner than in the previous tests.

The test results in output that is similar to the following:

ReadWriteLock test:

Start Resource writing (Thread=0) count: 0

Stop Resource writing (Thread=0) count: 1

Start Resource reading (Thread=1)count: 1

Start Resource reading (Thread=3)count: 1

Start Resource reading (Thread=5)count: 1

Start Resource reading (Thread=7)count: 1

Start Resource reading (Thread=9)count: 1

Stop Resource reading (Thread=1) count: 1

Stop Resource reading (Thread=3) count: 1

Stop Resource reading (Thread=5) count: 1

Stop Resource reading (Thread=7) count: 1

Stop Resource reading (Thread=9) count: 1

Start Resource writing (Thread=2) count: 1

Stop Resource writing (Thread=2) count: 2

Start Resource writing (Thread=4) count: 2

Stop Resource writing (Thread=4) count: 3

Start Resource writing (Thread=6) count: 3

Stop Resource writing (Thread=6) count: 4

Start Resource writing (Thread=8) count: 4

Stop Resource writing (Thread=8) count: 5

All ReadWriteLock threads have completed.

64

Module 14 (Optional): Threading and Asynchronous Programming

Threads and COM Interoperability

Topic Objective

To explain how managed threads call into a COM component.

Lead-in

COM components use apartments to synchronize access to resources.

!Thread calls to compatible COM apartment objects reduce costs

#Calls go directly to the COM objects, costly proxy-stub is eliminated

!A managed thread can indicate it will host an MTA or STA COM apartment using

#Thread.ApartmentState property or [STAThread] [MTAThread] attributes, for example:

[STAThread]

[STAThread]

public static void Main(string[] args) {//…} public static void Main(string[] args) {//…}

!The finalizer thread and all ThreadPool threads are MTA

!Managed objects can be called from any COM apartment in a free-threaded manner

#Except managed objects derived from ContextBoundObject

!Managed code calls out to COM objects following COM rules

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

COM components use apartments to synchronize access to resources. In contrast, managed objects use synchronized regions, synchronization primitives such as mutexes, locks and completion ports, and synchronized contexts to ensure that all shared resources are used in a thread-safe manner.

Calling a COM object from a managed thread

For interoperability, the runtime creates and initializes an apartment when a managed thread creates a COM object. A managed thread can create and enter a single-threaded apartment (STA) that contains only one thread, or a multithreaded apartment (MTA) that contains one or more threads. When a COM apartment and a thread-generated apartment are compatible, COM allows the calling thread to make calls directly to the COM object. If the apartments are incompatible, COM creates a compatible apartment and marshals all calls through a proxy in the new apartment.

On the first call to unmanaged code, the runtime calls CoInitializeEx to initialize the COM apartment as an MTA or STA apartment. As long as the proxy and stub are registered or the type library is registered, you do not have to set this property.

Module 14 (Optional): Threading and Asynchronous Programming

65

 

 

 

Setting the Thread.ApartmentState property

You can mark a managed thread to indicate that it will host a single-threaded or multithreaded apartment. The Thread.ApartmentState property returns and assigns the apartment state of a thread. If the property has not been set, the property returns ApartmentState.Unknown.

Whenever the COM object and the managed thread are in incompatible apartments, all calls on the object are made through a COM-created proxy.

The following example shows how to create an STA apartment-threaded COM object, AptSimple, from managed code:

using System.Threading; using APTOBJLib;

//…

AptSimple obj = new AptSimple (); obj.Counter = 1;

To eliminate the proxy and stub mechanism and significantly enhance performance, set the ApartmentState on the thread before creating the object, as follows:

using System.Threading; using APTOBJLib;

//…

Thread.CurrentThread.ApartmentState = ApartmentState.STA; AptSimple obj = new AptSimple ();

obj.Counter = 1;

You can set the ApartmentState property when the thread is in the

ThreadState.Unstarted or ThreadState.Running state; however, you can only set the property once for a thread. The two valid property states are singlethreaded apartment (STA) or multithreaded apartment (MTA).

66

Module 14 (Optional): Threading and Asynchronous Programming

Using the [STAThread] and [MTAThread] attributes

In some situations, a thread may already have called into unmanaged code before the ApartmentState could be set. As an alternative to setting the ApartmentState enumeration, you can apply the

System.STAThreadAttribute or System.MTAThreadAttribute to the main entry point of the application. By applying these attributes, you ensure that the main thread of an application is in the proper state.

For example, to ensure that the main thread of a Windows Form is apartment compatible with the Form’s control objects that must be created in a single threaded COM apartment, you can use the following code:

//…

[STAThread]

public static void Main(string[] args)

{

//…

}

Other COM vs. managed threading issues

Either apartment state has little effect on the managed portion of your application. The finalizer thread and all threads that are controlled by

ThreadPool are MTA.

Managed objects that are exposed to COM behave as if they had aggregated the free-threaded marshaler. In other words, they can be called from any COM apartment in a free-threaded manner. The only managed objects that do not exhibit this free-threaded behavior are those objects that derive from the

ContextBoundObject class.

In the managed execution environment, there is no support for the SynchronizationAttribute, unless you use contexts and context-bound managed instances. If you are using EnterpriseServices, your object must derive from ServicedComponent, which is itself derived from

ContextBoundObject.

When managed code calls out to COM objects, it always follows COM rules. In other words, it calls through COM apartment proxies and COM+ 1.0 context wrappers as dictated by OLE32.

Module 14 (Optional): Threading and Asynchronous Programming

67

 

 

 

Using Threads with Windows Forms Controls

Topic Objective

To describe how to use a Windows Forms control’s thread-safe method to make cross thread calls on the control.

Lead-in

Because Windows Forms controls can only execute on the thread on which they are created, they are not considered thread-safe.

!Controls can only execute methods on the thread on which they are created

#Except for calls to their thread-safe methods

!Background thread calls to a control must be marshaled

#Use thread-safe methods - Invoke, BeginInvoke, and

EndInvoke

#Methods take a reference to a delegate, typically an instance of the MethodInvoker delegate

!For example, a call to the aFormControl object’s UpdateProgress method

MethodInvoker mi = new

MethodInvoker mi = new

MethodInvoker(aFormControl.UpdateProgress);

MethodInvoker(aFormControl.UpdateProgress);

aFormControl.BeginInvoke(mi);

aFormControl.BeginInvoke(mi);

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

Windows Forms controls can only execute on the thread on which they are created. That is, they are not thread-safe. If you want to get or set properties, or call methods, on a control from a background thread, you must marshal the call to the thread that created the control.

There are five methods on a control that are safe to call from any thread:

InvokeRequired, Invoke, BeginInvoke, EndInvoke, and CreateGraphics. For all other method calls on a control, you should pass a delegate to that method as a parameter to the control’s Invoke or BeginInvoke methods. The Invoke and BeginInvoke methods ensure that their delegate parameter’s method is executed on the thread that owns this control’s underlying window handle.

68

Module 14 (Optional): Threading and Asynchronous Programming

The following table describes the invoke methods and specifies the method signatures for those methods.

Method

Signature and description

InvokeRequired public bool InvokeRequired { get ; }

 

Returns true if the caller must call Invoke when making method

 

calls to this control.

BeginInvoke

public IAsyncResult BeginInvoke(Delegate

 

method)

 

public IAsyncResult BeginInvoke(Delegate

 

method, Object[] args)

 

Executes the specified delegate on the thread that owns this

 

control’s underlying window handle. The delegate is called

 

asynchronously, and this method returns immediately. You can

 

call this method from any thread, even the thread that owns the

 

control’s handle. If the control’s handle does not exist yet, this

 

method will follow up the control’s parent chain until it finds a

 

control or form that has a window handle. If no appropriate

 

handle can be found, BeginInvoke throws an exception.

 

Exceptions within the delegate method are considered

 

untrapped and are sent to the application’s untrapped exception

 

handler.

EndInvoke

public Object EndInvoke(IAsyncResult

 

asyncResult)

 

Retrieves the return value of the asynchronous operation

 

represented by the IAsyncResult interface that is passed. If the

 

asynchronous operation has not completed, this method blocks

 

until the result is available.

Invoke

public Object Invoke(Delegate method)

 

public Object Invoke(Delegate method,

 

Object[] args)

 

Executes the specified delegate on the thread that owns this

 

control’s underlying window handle. The delegate is called

 

synchronously and this method returns after the invoked

 

method has returned. The return value is the result of the

 

invoked method. It is an error to call this method on the same

 

thread to which the control belongs.

The following code demonstrates how to create a background thread that uses a MethodInvoker to update a ProgressBar control at regular intervals:

Module 14 (Optional): Threading and Asynchronous Programming

69

 

 

 

//…

//Start the background thread

timerThread = new Thread(new ThreadStart(ThreadProc)); timerThread.IsBackground = true;

timerThread.Start();

//…

//This function is executed on a background thread –

//it marshalls calls to update the UI back to

//the foreground thread

public void ThreadProc() {

try {

MethodInvoker mi = new MethodInvoker(this.UpdateProgress);

while (true)

{

//Call BeginInvoke on the Form this.BeginInvoke(mi); Thread.Sleep(500) ;

}

}

//Thrown when the thread is interupted by the main // thread - exiting the loop

catch (ThreadInterruptedException e)

{

//Simply exit....

}

catch (Exception we)

{

}

}

//This function is called from the background thread private void UpdateProgress()

{

//Reset to start if required

if (progressBar1.Value == progressBar1.Maximum)

{

progressBar1.Value = progressBar1.Minimum ;

}

progressBar1.PerformStep() ;

}

//…

//Make sure to clean up the background thread in Dispose public override void Dispose()

{

if (timerThread != null)

{

timerThread.Interrupt(); timerThread = null;

}

}

70

Module 14 (Optional): Threading and Asynchronous Programming

Note If you are making multiple cross-thread calls to a control, it is much more efficient to create a new method that executes those calls and make a single cross-thread call to the new method.

Module 14 (Optional): Threading and Asynchronous Programming

71

 

 

 

Demonstration: Windows Forms Threading

Topic Objective

To demonstrate how to use a background thread in a Windows Forms application.

Lead-in

In this demonstration, you will see how to use a background thread in a Windows Forms application.

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

This demonstration shows how to use a background thread in a Windows Form application. The background thread will periodically advance the Windows Form progress bar.

The code for this demonstration is located in <install folder>\Democode\

Mod14\Demo14.5.

You should run this demonstration with breakpoints set on the ThreadProc method’s statement:

this.BeginInvoke(mi);

and on the UpdateProgress method’s statement:

progressBar1.PerformStep();

Start the application and observe the Microsoft Visual Studio® .NET Threads window.

Note To make the Visual Studio .NET Threads window visible, while the application is running, on the Debug menu, click Windows, and click Threads.

Click the form’s Start button, and when the program breaks, note the active thread. Continue to the next breakpoint and again note the active thread. You should observe that the BeginInvoke method marshaled the call to the Windows Forms main thread.

72

Module 14 (Optional): Threading and Asynchronous Programming

Best Practices for Working with Threads

Topic Objective

To provide a brief review of guidelines for working with threads.

Lead-in

If you need to implement threading in your applications, there are some guidelines and best practices of which you should be aware.

!Avoid providing static methods that alter static state

!Static state must be thread safe

!Instance state does not need to be thread safe

!Avoid taking locks whenever possible

!Be aware that deadlocks can result from calls in locked sections

!Use the System.Threading.Interlocked classes in preference to the lock statement where possible

!Avoid the need for synchronization if possible

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

Use the following best practices and rules as design guidelines for implementing threading in your applications:

!Avoid providing static methods that alter static state.

In common server scenarios, static state is shared across requests, which means that multiple threads can execute requests that access the same static state at the same time. This creates the potential for threading bugs. Consider using a design pattern that encapsulates data into instances that are not shared across requests.

!Static state must be thread-safe.

!Instance state does not need to be thread safe.

By default, a library is not thread safe. Adding locks to create thread-safe code decreases performance, increases lock contention, and creates the possibility for deadlock bugs to occur.

In common application models, only one thread at a time executes user code, which minimizes the need for thread safety. For this reason, the .NET Framework is not thread safe by default. In cases where you want to provide a thread-safe version of a class, use a GetSynchronized method to return a thread-safe instance of a type. For examples, see the System.Collections namespace in the .NET Framework SDK documentation.

!Design your library with consideration for the efficiency costs of running in a server scenario. Avoid taking locks whenever possible.

!Be aware of method calls in locked sections.

Deadlocks can result when a static method in class A calls static methods in class B and vice versa. If A and B both synchronize their static methods, this will cause a deadlock. You may discover this deadlock only under heavy threading stress.

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