1.线程锁的类型
线程锁类型有CComCriticalSection,CComAutoCriticalSection、 CComSafeDeleteCriticalSection、CComAutoDeleteCriticalSection、 CComFakeCriticalSection。每种锁都有它们的特定用途。
[c-sharp] view plain copy
// COM Sync Classes
class CComCriticalSection
{
public:
CComCriticalSection() throw()
{
memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
}
~CComCriticalSection()
{
}
HRESULT Lock() throw()
{
EnterCriticalSection(&m_sec);
return S_OK;
}
HRESULT Unlock() throw()
{
LeaveCriticalSection(&m_sec);
return S_OK;
}
HRESULT Init() throw()
{
HRESULT hRes = E_FAIL;
__try
{
InitializeCriticalSection(&m_sec);
hRes = S_OK;
}
// structured exception may be raised in low memory situations
__except(STATUS_NO_MEMORY == GetExceptionCode())
{
hRes = E_OUTOFMEMORY;
}
return hRes;
}
HRESULT Term() throw()
{
DeleteCriticalSection(&m_sec);
return S_OK;
}
CRITICAL_SECTION m_sec;
};
class CComAutoCriticalSection : public CComCriticalSection
{
public:
CComAutoCriticalSection()
{
HRESULT hr = CComCriticalSection::Init();
if (FAILED(hr))
AtlThrow(hr);
}
~CComAutoCriticalSection() throw()
{
CComCriticalSection::Term();
}
private :
HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called
HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called
};
class CComSafeDeleteCriticalSection : public CComCriticalSection
{
public:
CComSafeDeleteCriticalSection(): m_bInitialized(false)
{
}
~CComSafeDeleteCriticalSection() throw()
{
if (!m_bInitialized)
{
return;
}
m_bInitialized = false;
CComCriticalSection::Term();
}
HRESULT Init() throw()
{
ATLASSERT( !m_bInitialized );
HRESULT hr = CComCriticalSection::Init();
if (SUCCEEDED(hr))
{
m_bInitialized = true;
}
return hr;
}
HRESULT Term() throw()
{
if (!m_bInitialized)
{
return S_OK;
}
m_bInitialized = false;
return CComCriticalSection::Term();
}
HRESULT Lock()
{
// CComSafeDeleteCriticalSection::Init or CComAutoDeleteCriticalSection::Init
// not called or failed.
// m_critsec member of CComObjectRootEx is now of type
// CComAutoDeleteCriticalSection. It has to be initialized
// by calling CComObjectRootEx::_AtlInitialConstruct
ATLASSUME(m_bInitialized);
return CComCriticalSection::Lock();
}
private:
bool m_bInitialized;
};
class CComAutoDeleteCriticalSection : public CComSafeDeleteCriticalSection
{
private:
// CComAutoDeleteCriticalSection::Term should never be called
HRESULT Term() throw();
};
class CComFakeCriticalSection
{
public:
HRESULT Lock() throw() { return S_OK; }
HRESULT Unlock() throw() { return S_OK; }
HRESULT Init() throw() { return S_OK; }
HRESULT Term() throw() { return S_OK; }
};
2.线程锁的封装,实现锁类型的参数化
[cpp] view plain copy
template< class TLock >
class CComCritSecLock
{
public:
CComCritSecLock( TLock& cs, bool bInitialLock = true );
~CComCritSecLock() throw();
HRESULT Lock() throw();
void Unlock() throw();
// Implementation
private:
TLock& m_cs;
bool m_bLocked;
// Private to avoid accidental use
CComCritSecLock( const CComCritSecLock& ) throw();
CComCritSecLock& operator=( const CComCritSecLock& ) throw();
};
template< class TLock >
inline CComCritSecLock< TLock >::CComCritSecLock( TLock& cs, bool bInitialLock ) :
m_cs( cs ),
m_bLocked( false )
{
if( bInitialLock )
{
HRESULT hr;
hr = Lock();
if( FAILED( hr ) )
{
AtlThrow( hr );
}
}
}
template< class TLock >
inline CComCritSecLock< TLock >::~CComCritSecLock() throw()
{
if( m_bLocked )
{
Unlock();
}
}
template< class TLock >
inline HRESULT CComCritSecLock< TLock >::Lock() throw()
{
HRESULT hr;
ATLASSERT( !m_bLocked );
hr = m_cs.Lock();
if( FAILED( hr ) )
{
return( hr );
}
m_bLocked = true;
return( S_OK );
}
template< class TLock >
inline void CComCritSecLock< TLock >::Unlock() throw()
{
ATLASSUME( m_bLocked );
m_cs.Unlock();
m_bLocked = false;
}
3.ATL线程模型定义
[cpp] view plain copy
class CComMultiThreadModel
{
public:
static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}
static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}
typedef CComAutoCriticalSection AutoCriticalSection;
typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;
typedef CComCriticalSection CriticalSection;
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
};
class CComSingleThreadModel
{
public:
static ULONG WINAPI Increment(LPLONG p) throw() {return ++(*p);}
static ULONG WINAPI Decrement(LPLONG p) throw() {return --(*p);}
typedef CComFakeCriticalSection AutoCriticalSection;
typedef CComFakeCriticalSection AutoDeleteCriticalSection;
typedef CComFakeCriticalSection CriticalSection;
typedef CComSingleThreadModel ThreadModelNoCS;
};
class CComMultiThreadModelNoCS
{
public:
static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}
static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}
typedef CComFakeCriticalSection AutoCriticalSection;
typedef CComFakeCriticalSection AutoDeleteCriticalSection;
typedef CComFakeCriticalSection CriticalSection;
typedef CComMultiThreadModelNoCS ThreadModelNoCS;
};
ATL中把不同线程模型下引用计数的实作封装到同一个函数中:加法是Increment(),减法是Decrement() 。三个代表不同线程模型的类:CComSingleThreadModel、CComMultiThreadModel 、CComMultiThreadModelNoCS 中均实作了这两个函数。这样,我们只需要把线程模型当作模板参数传递给对象,对象就能获得正确的引用计数操作动作。
其中有3种临界区 CComCriticalSection 、CComAutoCriticalSection 、CComFakeCriticalSection 。每一个临界区都提供了统一的4种操作来操作临界区:Lock() 、Unlock() 、Init() 、Term() 。我们在程序中使用“临界区”时,只需要调用这四种操作就可以达到保护数据成员不被其他线程修改的目的。
4.服务器的默认线程模型
[cpp] view plain copy
#if defined(_ATL_SINGLE_THREADED)
#if defined(_ATL_APARTMENT_THREADED) || defined(_ATL_FREE_THREADED)
#pragma message ("More than one global threading model defined.")
#endif
typedef CComSingleThreadModel CComObjectThreadModel;
typedef CComSingleThreadModel CComGlobalsThreadModel;
#elif defined(_ATL_APARTMENT_THREADED)
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_FREE_THREADED)
#pragma message ("More than one global threading model defined.")
#endif
typedef CComSingleThreadModel CComObjectThreadModel;
typedef CComMultiThreadModel CComGlobalsThreadModel;
#elif defined(_ATL_FREE_THREADED)
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_APARTMENT_THREADED)
#pragma message ("More than one global threading model defined.")
#endif
typedef CComMultiThreadModel CComObjectThreadModel;
typedef CComMultiThreadModel CComGlobalsThreadModel;
#else
#pragma message ("No global threading model defined")
#endif
ATL内部使用CComObjectThreadModel来保护组件内部实例数据,CComGlobalThreadModel来保护全局和静态数据。
ATL提供了 CComObjectRootEx模板类,来封装上面关于引用计数的操作以及临界区的操作。只要提供给CComObjectRootEx一个代表其线程模型的模板参数,它就能实作出InternalAddRef()、InternalRelease()以及Lock()和UnLock()四个统一的操作界面。
经过了这么多层封装,ATL 已经把AddRef()和Release()所需要的操作全部实作出来了,可是ATL还是没有迈出最后的一步——没有把这些操作整合进AddRef()和 Release(),这是因为ATL还要考虑聚合的因素。在聚合的情况下,COM对象的AddRef()和Release()操作都和独立激活时候完全不同。