RAD Studio |  |

Choosing a Threading Model
Writing an object that supports the free threading model | Writing an object that supports the apartment threading model | Writing an object that supports the neutral threading model
Collapse All

When creating an object using a wizard, you select a threading model that your object agrees to support. By adding thread support to your COM object, you can improve its performance, because multiple clients can access your application at the same time.

The following table lists the different threading models you can specify.

Threading models for COM objects

Threading model | Description | Implementation pros and cons
Single | The server provides no thread support. COM serializes client requests so that the application receives one request at a time. | Clients are handled one at a time so no threading support is needed. No performance benefit.
Apartment (or Single-threaded apartment) | COM ensures that only one client thread can call the object at a time. All client calls use the thread in which the object was created. | Objects can safely access their own instance data, but global data must be protected using critical sections or some other form of serialization. The thread's local variables are reliable across multiple calls. Some performance benefits.
Free (also called multi-threaded apartment) | Objects can receive calls on any number of threads at any time. | Objects must protect all instance and global data using critical sections or some other form of serialization. Thread local variables are not reliable across multiple calls.
Both | This is the same as the Free-threaded model except that outgoing calls (for example, callbacks) are guaranteed to execute in the same thread. | Maximum performance and flexibility. Does not require the application to provide thread support for parameters supplied to outgoing calls.
Neutral | Multiple clients can call the object on different threads at the same time, but COM ensures that no two calls conflict. | You must guard against thread conflicts involving global data and any instance data that is accessed by multiple methods. This model should not be used with objects that have a user interface (visual controls). This model is only available under COM+. Under COM, it is mapped to the Apartment model.

Note: Local variables (except those in callbacks) are always safe, regardless of the threading model. This is because local variables are stored on the stack and each thread has its own stack. Local variables may not be safe in callbacks when using free-threading.
The threading model you choose in the wizard determines how the object is registered in the system Registry. You must make sure that your object implementation adheres to the threading model you have chosen. For general information on writing thread-safe code, see Writing multi-threaded applications.

For in-process servers, setting the threading model in the wizard sets the threading model key in the CLSID registry entry.

Out-of-process servers are registered as EXE, and Delphi initializes COM for the highest threading model required. For example, if an EXE includes a free-threaded object, it is initialized for free threading, which means that it can provide the expected support for any free-threaded or apartment-threaded objects contained in the EXE. To manually override threading behavior in EXEs, use the CoInitFlags variable.

Writing an object that supports the free threading model

Use the free threading (or both) model rather than apartment threading whenever the object needs to be accessed from more than one thread. A common example is a client application connected to an object on a remote machine. When the remote client calls a method on that object, the server receives the call on a thread from the thread pool on the server machine. This receiving thread makes the call locally to the actual object; and, because the object supports the free threading model, the thread can make a direct call into the object.

If the object supported the apartment threading model instead, the call would have to be transferred to the thread on which the object was created, and the result would have to be transferred back into the receiving thread before returning to the client. This approach requires extra marshaling.

To support free threading, you must consider how instance data can be accessed for each method. If the method is writing to instance data, you must use critical sections or some other form of serialization, to protect the instance data. Likely, the overhead of serializing critical calls is less than executing COM's marshaling code.

Note that if the instance data is read-only, serialization is not needed.

Free-threaded in-process servers can improve performance by acting as the outer object in an aggregation with the free-threaded marshaler. The free-threaded marshaler provides a shortcut for COM's standard thread handling when a free-threaded DLL is called by a host (client) that is not free-threaded.

To aggregate with the free threaded marshaler, you must

- Call CoCreateFreeThreadedMarshaler, passing your object's IUnknown interface for the resulting free-threaded marshaler to use: CoCreateFreeThreadedMarshaler(self as IUnknown, FMarshaler); CoCreateFreeThreadedMarshaler(static_cast<IUnknown *>(this), &FMarshaler);. This line assigns the interface for the free-threaded marshaler to a class member, FMarshaler.
- Using the Type Library Editor, add the IMarshal interface to the set of interfaces your CoClass implements.
- In your object's QueryInterface method, delegate calls for IDD_IMarshal to the free-threaded marshaler (stored as FMarshaler above).

Warning: The free-threaded marshaler violates the normal rules of COM marshaling to provide additional efficiency. It should be used with care. In particular, it should only be aggregated with free-threaded objects in an in-process server, and should only be instantiated by the object that uses it (not another thread).
Writing an object that supports the apartment threading model

To implement the (single-threaded) apartment threading model, you must follow a few rules:

- The first thread in the application that gets created is COM's main thread. This is typically the thread on which WinMain was called. This must also be the last thread to uninitialize COM.
- Each thread in the apartment threading model must have a message loop, and the message queue must be checked frequently.
- When a thread gets a pointer to a COM interface, that pointer may only be used in that thread.

The single-threaded apartment model is the middle ground between providing no threading support and full, multi-threading support of the free threading model. A server committing to the apartment model promises that the server has serialized access to all of its global data (such as its object count). This is because different objects may try to access the global data from different threads. However, the object's instance data is safe because the methods are always called on the same thread.

Typically, controls for use in Web browsers use the apartment threading model because browser applications always initialize their threads as apartment.

Writing an object that supports the neutral threading model

Under COM+, you can use another threading model that is in between free threading and apartment threading: the neutral model. Like the free-threading model, this model allows multiple threads to access your object at the same time. There is no extra marshaling to transfer to the thread on which the object was created. However, your object is guaranteed to receive no conflicting calls.

Writing an object that uses the neutral threading model follows much the same rules as writing an apartment-threaded object, except that you do need to guard instance data against thread conflicts if it can be accessed by different methods in the object's interface. Any instance data that is only accessed by a single interface method is automatically thread-safe.

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!