65.9K
CodeProject 正在变化。 阅读更多。
Home

COM 对象的智能临界区包装器

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (1投票)

2000 年 3 月 30 日

viewsIcon

84911

一个非常简单的类,它包装了 win32 CRITICAL_SECTION。非常适合 COM STA 或 MTA。

引言

越来越多的 COM 对象被编写为“Both”线程,因为这使得在 COM STA 或 MTA 中创建对象成为可能。如果创建“Both”线程 COM 对象的线程通过使用 CoInitialize()CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)OleInitialize() 初始化为位于 STA 中,则该对象将在同一 STA 中创建。如果线程改为通过使用 CoInitializeEx(NULL, COINIT_MULTITHREADED) 初始化为位于 MTA 中,则该对象将在进程的唯一 MTA 中创建。

因此,对象的开发人员被迫为多个线程的同时访问编写代码,通常通过使用临界区。请注意,任何全局和静态变量都需要受到保护。我在这里展示的是优化保护对象实例状态的代码。我还想指出,如果对象聚合了自由线程封送器 (FTM),则不应使用此技术。类 CComSmartAutoCriticalSection 是一个非常简单的类,它包装了一个 WIN32 CRITICAL_SECTION。该类的定义如下

//////////////////////////////////////////////////////////////////////////////// 
// CComSmartAutoCriticalSection 
// 
class CComSmartAutoCriticalSection 
{ 
public: 
	CComSmartAutoCriticalSection() 
	{ 
		if (SUCCEEDED(::CoInitialize(NULL))) 
		{ 
			::CoUninitialize(); 

			m_bInMTA = FALSE; 
		} 
		else 
		{ 
			m_bInMTA = TRUE; 
		} 

		if (m_bInMTA) 
			::InitializeCriticalSection(&m_csSafeAccess); 
	} 

	~CComSmartAutoCriticalSection() 
	{ 
		if (m_bInMTA) 
			::DeleteCriticalSection(&m_csSafeAccess); 
	} 

	void Lock() 
	{ 
		if (m_bInMTA) 
			::EnterCriticalSection(&m_csSafeAccess); 
	} 

	void Unlock() 
	{ 
		if (m_bInMTA) 
			::LeaveCriticalSection(&m_csSafeAccess); 
	} 

private: 
	BOOL              m_bInMTA; 
	CRITICAL_SECTION  m_csSafeAccess; 
}; 

构造函数检测创建线程是否属于 COM STA 或 MTA,并初始化私有成员变量 m_bInMTACoInitialize() 调用如果调用线程属于 STA 将返回 S_FALSE,如果调用线程属于 MTA 将返回 RPC_E_CHANGED_MODE。如果对象正在 MTA 中创建,则初始化 m_csSafeAccess 临界区。

如果对象在 MTA 中创建,则析构函数会删除 m_csSafeAccess 临界区。

Lock()Unlock() 方法分别调用 WIN32 EnterCirticalSection()LeaveCriticalSection() API,仅当对象在 MTA 中创建时才调用。

用法

在实现 COM 对象的 C++ 类中,定义一个类型为 CComSmartAutoCriticalSection 的成员变量。

class ATL_NO_VTABLE CSomeCOMClass : <inheritance list> 
{ 
private: 
	CComSmartAutoCriticalSection m_csSafeAccess; 
} 

接口属性和方法的实现函数应包装在 Lock()Unlock() 函数中。

STDMETHODIMP CSomeCOMClass::SomeMethod() 
{ 
	HRESULT hResult = S_OK; 


	m_csSafeAccess.Lock(); 

	... // Code to do what the method does. 

	m_csSafeAccess.Unlock(); 

	return hResult; 
} 
© . All rights reserved.