Lesson 4: Threading Models

In Chapter 5, you learned how you can improve the performance of an application by running concurrent tasks on multiple threads. Because a single instance of a COM object can be accessed simultaneously by any number of client threads, you must make sure that access to your COM object is properly synchronized.

Generally, object synchronization is handled by the operating system. It is important to know how the operating system handles object synchronization so that you can create components that perform efficiently in a multithreaded environment. COM defines four threading models that simplify the issues surrounding multithreaded component development.

After this lesson, you will be able to:

  • Describe the four COM threading models.
  • Describe the advantages and disadvantages of using each of the threading models.
  • Identify the registry keys used to identify component threading models.
Estimated lesson time: 30 minutes

COM Threading Models

A threading model describes the type and degree of thread safety implemented by a component. A COM component can support one of the following four threading models:

  • The single-threading model
  • The apartment-threading model
  • The free-threading (multi-threaded) model
  • The mixed-threading model (supports both apartment and free-threading)

Before a client thread can use a COM object, it must initialize the COM libraries by calling the CoInitializeEx() API function. When it does this, it can specify the model it uses for calls to the objects that it creates. A client thread can specify that it will use the apartment-threading model or the free-threading model.

Any client application, regardless of its own threading arrangement, can safely access a COM component built from any threading model. If a client's threading is not compatible with that of the server, the COM run-time library takes steps to ensure that the client and server communicate in a thread-safe manner. However, these measures can adversely affect the performance of the application.

Single-Threading Model

A COM server that supports the single-threading model requires that all client requests for object services are queued on a single thread. Single-threaded COM servers are suitable for use with only single-threaded applications—which means legacy code. Access to a single-threaded component is very efficient for the thread that actually creates the component. The thread that first creates the component can obtain direct pointers to the interfaces exposed by the component. However, subsequent requests from other threads cannot directly access the interface pointers because the server process only supports a single thread. All subsequent threads must marshal interface requests between a proxy on the client and a stub on the server main thread. Calls made by external threads through the proxy/stub are placed in the server message queue. External threads experience poor performance as a result of the overhead involved in marshaling, and because the direct interface requests made by the creator thread take priority over the requests waiting in the message queue.

Apartment-Threading Model

The apartment-threading model enables all clients to obtain a direct pointer to a component interface, without going through proxy and stub services. An apartment is a conceptual entity that provides a logical structure for thread concurrency. An apartment is created when a thread calls the CoInitializeEx() API function to initialize the COM libraries. An apartment is associated with one or more threads, and one or more COM object instances. As long as the objects created within an apartment support the apartment-threading model, all threads in an apartment can obtain direct interface pointers to all objects in the apartment.

The terminology surrounding apartment threading can be confusing because there are two types of apartments: single-threaded apartments (STAs) and multithreaded apartments (MTAs). The distinction between the two is as follows:

  • STAs implement the apartment-threading model.
  • MTAs implement the free-threading model.

A process can contain any number of STAs (each one containing a single thread) but only one MTA to which any number of threads can belong.

Single-Threaded Apartments

STAs have only one thread that creates and calls objects. Because only one thread can access those objects in the apartment, the objects are effectively synchronized.

Components that support STAs perform better than those that support the single-threaded model. You can use the STA model to write more efficient code. At the same time a thread in one STA waits for an operation to finish, another STA can allow the interim execution of a thread in still another STA.

When a thread calls CoInitializeEx() with the COINIT_APARTMENTTHREADED parameter, the thread creates an STA. A thread that is initialized as an STA is known as an STA thread type. A COM object that is instantiated by an STA thread type can be accessed by that thread only. This protects COM objects from being accessed by multiple threads simultaneously.

Synchronizing Threads

Threads that want to use a COM object residing in another apartment must have the interface pointers of the COM object marshaled to them. The threads cannot have a direct interface pointer because this would allow multiple threads to access the object, which violates the STA model rules.

By marshaling an interface pointer to other threads, COM uses window messages to synchronize multiple threads. Each STA thread type has a message loop that receives marshaled calls from other processes and other apartments in the same process. When a client makes a call to a server object, the marshaling code places a corresponding window message in the server thread's message queue. Multiple thread calls are queued in the message queue while the object's STA thread type process each message, one at a time.

Passing Interface Pointers

When interface pointers are passed between apartments, the pointers must be marshaled. You use the CoMarshalInterThreadInterfaceInStream() COM API function to marshal interface pointers between threads in the same process. For more information about the CoMarshalInterThreadInterfaceInStream() function, refer to the Visual Studio Help file.

Multithreaded Apartments

MTAs are also called free-threading models. This model differs from an STA in that multiple threads can reside in one apartment. MTAs provide the highest performance.

NOTE
The MTA model was introduced in Windows NT 4.0 and is also available in Windows 95 with DCOM95 installed.

All threads that call CoInitalizeEx() with the COINIT_MULTITHREADED parameter live in a single MTA and are known as MTA thread types. Unlike the STA model, there is only one MTA per process. When additional MTA threads are initialized as MTA thread types, they live in the same apartment. In addition, there is no need to marshal between threads.

COM objects created by MTA thread types must be thread safe and must provide their own synchronization code. By removing the bottleneck created by marshaling, MTAs provide the highest performance and throughput on the server side.

In the MTA model, any thread can call a COM object concurrently, and COM does not synchronize the calls. Because synchronization is not provided, COM objects written for an MTA must be thread safe. Therefore, synchronization objects such as events, mutexes, and semaphores (as described in Lesson 3 of Chapter 5) must be used to protect a component's static and global data.

Threading-Model Registry Keys

In-process servers must enter their threading model in the registry because in-process servers typically do not call CoInitializeEx(). When a client creates an in-process server COM object, COM uses the threading-model registry key to determine if marshaling code is necessary for the returned interface pointer.

To indicate the type of threading model in the registry, the named ThreadingModel value is created under the following key:

HKEY_CLASSES_ROOT\CLSID\[component CLSID]\InProcServer32

ThreadingModel can contain one of the following values:

  • None Supports the single-threading model only
  • Apartment Supports the STA model
  • Free Supports the MTA model only
  • Both Supports both the STA and MTA model

Lesson Summary

COM defines four threading models that simplify the issues surrounding the synchronization of access to components in a multithreaded environment. The single-threading model requires that all client requests for object services are queued on a single thread. The apartment-threading model uses an STA to define a logical grouping of components that are only accessed by a single thread. The free-threading model groups thread-safe components together in a single MTA. If a component supports the mixed-threading model, threads in a single or a multi-threaded apartment can safely access it.

An apartment is created when a thread calls the CoInitializeEx() API function to initialize the COM libraries. Use arguments to the CoInitializeEx() function to specify an STA or an MTA type thread. In-process servers typically do not call CoInitializeEx()—they specify their threading model in a registry entry.

COM ensures that communication between clients and objects with different threading models is conducted in a thread-safe manner, marshaling the data if necessary. When you pass interface pointers between apartments, you must marshal the interface using the CoMarshalInterThreadInterfaceInStream() COM API function.



Microsoft Press - Desktop Applications with Microsoft Visual C++ 6. 0. MCSD Training Kit
Desktop Applications with Microsoft Visual C++ 6.0 MCSD Training Kit
ISBN: 0735607958
EAN: 2147483647
Year: 1999
Pages: 95

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net