Agility in Server Components

Neil Allain
MicroCrafts

October 10, 1997

Introduction

Using the Active Template Library (ATL), it's easy to make an Active Server Pages (ASP) component that supports both free-threaded and apartment-threaded threading models. However, you may not be gaining the performance benefits you had hoped for. To understand why, let's take a quick look at threading models and how components support them. It is also helpful to review the threading model summary provided at the end of this article, although developers should note this summary applies only to version 4.0 of Internet Information Server (IIS).

Understanding the Threading Model

If any thread wants to use Component Object Model (COM) objects, it must first call some form of CoInitialize (OleInitialize or CoInitializeEx). Once called, you have bound the thread to use a certain threading model, either single-threaded apartment or multi-threaded apartment. (The single-threaded apartment model is generally called the apartment model, while the multithreaded apartment model is generally called the multithreaded or free-threaded model.)

Every application has one and only one multithreaded apartment (which may have zero or more threads associated with it), and has one single-threaded apartment for every thread that was initialized as single-threaded. Objects marked as apartment-threaded belong in the single-threaded apartment thread in which they were created. Objects marked as free-threaded always belong to the multithreaded apartment, regardless of the thread in which they were created. So a free-threaded object created in a single-threaded apartment would actually belong to a different apartment (the multithreaded apartment), and an apartment-threaded object created in a multithreaded apartment would belong to its own single-threaded apartment (possibly creating a new thread for that apartment). An object that is marked as supporting both threading models, however, always belongs to the apartment in which it was created. This means it is an apartment-threaded object when created in a single-threaded apartment, and it is a free-threaded object when created in a multithreaded apartment. It is not both, however, and still belongs to one and only one apartment.

Why does it matter what apartment an object belongs to? Any calls to an object from an apartment other than the one it belongs to must go through a proxy rather than use the object directly. This is considerably slower than using the object directly, not to mention the fact that all your hard work in making your object thread-safe would count for nothing if your object gets created in a single-threaded apartment. There is a solution to this problem, and ATL makes it very easy.

Making Your Server Component Agile

The solution is to aggregate a free-threaded marshaler. When an interface pointer is being marshaled between two apartments, a free-threaded marshaler will supply a direct pointer to the object rather than a proxy. This enables you to take full advantage of multithreading, regardless of the apartment in which an object was created. An object that aggregates a free-threaded marshaler is called agile. If you are using the ATL Wizard to create an object, simply select the Free Threaded Marshaler check box and the Yes radio button under Aggregation to make the object agile:

Figure 1. ATL Object Wizard Properties

If you want to make an existing object agile, it requires only a little more work. In the class declaration, add the following few lines (the new lines are in italicized boldface type):

class ATL_NO_VTABLE CMyObject : 
…
{
public:
…
DECLARE_GET_CONTROLLING_UNKNOWN()

BEGIN_COM_MAP(CMyObject)
…
 COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
…
END_COM_MAP()

 HRESULT FinalConstruct()
 {
 return CoCreateFreeThreadedMarshaler(
  GetControllingUnknown(), &m_pUnkMarshaler.p );
 }
 void FinalRelease()
 {
 m_pUnkMarshaler.Release();
 }

 CComPtr<IUnknown>   m_pUnkMarshaler;
…
};

These are exactly the lines the ATL Wizard adds for you when you are creating a new object.

Now that your object is agile, it's doing what you originally expected it to do when you marked it as supporting both threading models, and it can be accessed directly from any thread of execution. Writing agile server components will boost your Web application's performance.

IIS 4.0 Threading Model Summary

Andrew Sigal
Software Design Engineer
Microsoft Corporation

This model applies to Internet Information Server version 4.0 only.

Both

(+Free-Threaded Marshaler)

Single Free Apartment
Application

<OBJECT>

tag objects

Access is direct.

Object runs in current user security context.

Accesses are not serialized.

Access through proxy via GIP.

Object runs in SYSTEM context.

Accesses are serialized.

Cannot access ObjectContext.

Access through proxy via GIP.

Object runs in SYSTEM context.

Accesses are not serialized.

Cannot access ObjectContext.

Access through proxy via GIP.

Object runs in SYSTEM context.

Accesses are serialized.

Application

Properties

(i.e., Application ("obj") = )

Access is direct.

Object runs in current user security context.

Accesses are not serialized.

Access through proxy via GIP.

Object runs in SYSTEM context.

Accesses are serialized.

Cannot access ObjectContext.

Access through proxy.

Object runs in SYSTEM context.

Accesses are serialized.

Cannot access ObjectContext.

Session is locked down.

Access is direct.

Object runs in current user security context.

Accesses are serialized.

Session is locked down.

Session Objects Access is direct.

Object runs in current user security context.

Accesses are not serialized.

Access through proxy.

Object runs in SYSTEM context.

Accesses are serialized.

Cannot access ObjectContext.

Session is locked down.

Access through proxy.

Object runs in SYSTEM context.

Accesses are serialized.

Cannot access ObjectContext.

Session is locked down.

Access is direct.

Object runs in current user security context.

Accesses are serialized.

Session is locked down.

Page Objects Access is direct.

Object runs in current user security context.

Accesses are not serialized.

Access through proxy.

Object runs in system context.

Accesses are serialized.

Cannot access ObjectContext.

Access through proxy.

Object runs in system context.

Accesses are serialized.

Cannot access ObjectContext.

Access is direct.

Object runs in current user security context.

Accesses are serialized.


Author Neil Allain is a developer on the IIS team, working on component development.

Andrew Sigal is a lead developer on the IIS team.