TN064:ActiveX 控件中的单元模型线程
注意
以下技术说明在首次包括在联机文档中后未更新。 因此,某些过程和主题可能已过时或不正确。 要获得最新信息,建议你在联机文档索引中搜索热点话题。
此技术说明介绍如何在 ActiveX 控件中启用单元模型线程。 请注意,单元模型线程仅在 Visual C++ 4.2 或更高版本中受支持。
什么是单元模型线程
单元模型是支持多线程容器应用程序中的嵌入对象(如 ActiveX 控件)的方法。 尽管应用程序可能有多个线程,但嵌入对象的每个实例都将分配给一个“单元”,该单元仅在一个线程上执行。 换句话说,对控件实例的所有调用都将在同一线程上发生。
但是,同一类型的控件的不同实例可以分配给不同的单元。 因此,如果控件的多个实例共享任何公共数据(例如静态数据或全局数据),则需要通过同步对象(如关键分区)保护对此共享数据的访问。
有关单元线程模型的完整详细信息,请参阅 OLE 程序员参考中的进程和线程。
为什么支持单元模型线程
支持单元模型线程的控件可用于也支持单元模型的多线程容器应用程序中。 如果未启用单元模型线程,将限制可以使用控件的潜在容器集。
启用单元模型线程对于大多数控件来说很容易,尤其是在它们几乎没有共享数据或没有共享数据的情况下。
保护共享数据
如果控件使用共享数据(如静态成员变量),则应使用关键分区保护对该数据的访问,以防止多个线程同时修改数据。 若要为此设置关键分区,请在控件的类中声明类 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();
...
}
注册单元模型感知控件
支持单元模型线程的控件应在注册表中指示此功能,方法是在类 ID\InprocServer32 键下在其类 ID 注册表项下添加名为“ThreadingModel”的值为“Apartment”。 若要使此密钥自动注册控件,请将第六个参数中的 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。