注释
自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。
此技术说明介绍如何在 ActiveX 控件中启用单元模型线程。 请注意,单元模型线程仅在 Visual C++ 4.2 或更高版本中受支持。
什么是 Apartment-Model 线程
单元模型是支持多线程容器应用程序中嵌入对象(如 ActiveX 控件)的方法。 尽管应用程序可能有多个线程,但嵌入对象的每个实例将分配给一个“单元”,该单元将仅在一个线程上执行。 换句话说,对控件实例的所有调用都将在同一线程上发生。
但是,同一类型的控件的不同实例可以分配给不同的公寓。 因此,如果控件的多个实例共享任何通用数据(例如静态或全局数据),则需要通过同步对象(如关键部分)保护对此共享数据的访问。
有关单元线程模型的完整详细信息,请参阅 OLE 程序员参考中的进程和线程。
为什么支持 Apartment-Model 线程处理
支持单元模型线程的控件可在支持单元模型的多线程容器应用程序中使用。 如果未启用单元模型线程,则会限制可以使用控件的潜在容器集。
对于大多数控件而言,启用单元模型线程很容易,尤其是在它们几乎没有共享数据或没有共享数据的情况下。
保护共享数据
如果控件使用共享数据(如静态成员变量),则应使用关键节保护对该数据的访问,以防止多个线程同时修改数据。 若要为此设置关键节,请在控件的类中声明类 CCriticalSection
的静态成员变量。
Lock
无论代码访问共享数据,请使用此关键节对象的和Unlock
成员函数。
例如,请考虑需要维护所有实例共享的字符串的控件类。 此字符串可以在静态成员变量中维护,并由关键节保护。 控件的类声明将包含以下项:
class CSampleCtrl : public COleControl
{
...
static CString _strShared;
static CCriticalSection _critSect;
};
类的实现将包括这些变量的定义:
int CString CSampleCtrl::_strShared;
CCriticalSection CSampleCtrl::_critSect;
然后,关键部分可以保护对 _strShared
静态成员的访问:
void CSampleCtrl::SomeMethod()
{
_critSect.Lock();
if (_strShared.Empty())
_strShared = "<text>";
_critSect.Unlock();
...
}
注册单元Model-Aware 控件
支持单元模型线程的控件应通过在类 ID\InprocServer32 键下的类 ID 注册表项下添加名为“ThreadingModel”的命名值“ThreadingModel”来指示此功能。 若要使此密钥自动注册控件,请将第六个参数中的 afxRegApartmentThreading 标志传递给 AfxOleRegisterControlClass
:
BOOL CSampleCtrl::CSampleCtrlFactory::UpdateRegistry(BOOL bRegister)
{
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_SAMPLE,
IDB_SAMPLE,
afxRegApartmentThreading,
_dwSampleOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid,
m_lpszProgID);
}
如果控件项目是由 Visual C++ 版本 4.1 或更高版本中的 ControlWizard 生成的,则代码中已存在此标志。 注册线程模型无需更改。
如果项目是由早期版本的 ControlWizard 生成的,则现有代码将具有布尔值作为第六个参数。 如果现有参数为 TRUE,请将其更改为 afxRegInsertable | afxRegApartmentThreading。 如果现有参数为 FALSE,请将其更改为 afxRegApartmentThreading。
如果控件未遵循单元模型线程的规则,则不得在此参数中传递 afxRegApartmentThreading 。