CComObjectCached and scalability

This is related to the P.D.² section of my last blog entry.

In the released versions of ATL, CComObjectCached has a potential scalability issue. That class is the one implementing IClassFactory when your component is a DLL (vs. an EXE):

#if defined(_WINDLL) | defined(_USRDLL)

#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectCached< cf > > _ClassFactoryCreatorClass;

#else

Jim Springfield who is an architect on the C++ codegen team was kind enough to send me this:

There is a way to fix this on the component side. The whole reason for the critical section goes back to an issue with InterlockedIncrement and InterlockedDecrement on Win95 and NT3.51. On those platforms, the Interlocked functions are not guaranteed to return the actual value, but just one that is correct in sign (i.e. positive, negative, or zero). Since the code needs to do stuff for values of 1 and 2, another locking mechanism is needed, and that is what m_csCached is used for.

If you know you are running on NT4 or later, or Win98 or later, then you can get rid of that critical section and use the return values directly. So, if you change the CComObjectCached code (in atlcom.h) to the following you should be OK and avoid that critical section. If the customer isn’t comfortable changing ATL’s code, you should be able to make a copy of CComObjectCached (i.e CComObjectMyCached) and define your own DECLARE_CLASS_FACTORY style macro to use your implementation.

 

STDMETHOD_(ULONG, AddRef)() throw()

{

      ULONG l = InternalAddRef();

      if (l == 2)

            _pAtlModule->Lock();

      return l;

}

 

STDMETHOD_(ULONG, Release)() throw()

{

      ULONG l = InternalRelease();

      if (l == 0)

            delete this;

      else if (l == 1)

            _pAtlModule->Unlock();

      return l;

}

If you want to learn more about that class, I would advise you to get any of those books:
- Inside ATL
- ATL Internals
- Professional ATL COM Programming