COM对象生命周期

时间:2014-12-21 08:45:07

标签: c++ visual-c++ com

考虑以下情况:

此代码由线程A执行:

CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
globalSomeSTAComObject.CreateInstance((__uuidof(CLSID_SomeSTAComObject));
return 0;

现在线程A完成之后执行它default STA“继承”globalSomeSTAComObject,它可以被其他线程使用吗?
或者这个对象变得无法使用?

关于线程A的相同问题,但现在认为该对象是在MTA线程上创建的MTA Com对象 当线程A完成时,它的执行是否MTA Com对象在Multithreaded Apartment内仍然存在且可以使用?

MSXML2::IXMLDOMDocumentPtr xml;

unsigned __stdcall CreateXml(void*)
{
    CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    xml.CreateInstance(__uuidof(MSXML2::FreeThreadedDOMDocument60));
    xml->load("c:\\test.xml");
    return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{   
    CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    HANDLE handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, CreateXml, nullptr, 0, nullptr));
    WaitForSingleObject(handle, INFINITE);
    long numOfSections = xml->documentElement->childNodes->length;  //This works why ?
    xml.Release();
    CoUninitialize();
    return 0;
}

请不要在CreateXml我故意没有调用CoUninitialize因为我想知道这个场景中xml对象的状态是什么。

2 个答案:

答案 0 :(得分:0)

它取决于COM对象本身和创建它的线程的线程模型。

如果对象是单元线程的,它将存在于自己的STA中。如果STA线程创建对象,则线程在与对象相同的STA中运行,并接收指向该对象的直接指针。如果MTA线程创建对象,则创建新STA并且线程接收STA中对象的代理。在任何一种情况下,如果其他线程想要访问它,则必须对该对象进行编组。

如果对象是多线程的,它将存在于MTA中。如果STA线程创建对象,则线程接收MTA中对象的代理。如果MTA线程创建对象,它将接收指向该对象的直接指针。该对象可以由其他MTA线程直接访问,但如果由STA线程访问,则必须进行编组。

如果对象是自由线程的,则如果由STA线程创建,它将存在于STA中,并且如果由MTA线程创建,它将存在于MTA中。然后适用上述规则。

在MSDN上详细讨论了这个主题:

Processes, Threads, and Apartments

Understanding and Using COM Threading Models

COM+ Threading Models

答案 1 :(得分:0)

COM对象只要认为有对它的引用就会存在,即引用计数大于零。当调用CoUninitialize时,将发布到公寓对象的所有跨公寓链接。释放存根,减少实际物体的数量。引用计数。通过返回RPC错误HRESULT,会通过引用代理通知并在除引用计数之外的任何其他内容中失败。

但是,我认为在没有必要调用CoUninitialize的情况下退出一个线程没有指定的行为。我可以看到没有任何反应的场景,所以你最终可能会遇到这种情况。过时的STA对象链接,消息循环永远不会运行,因为你拉下了它下面的地毯(线程),或者死了MTA对象,如果没有至少一个MTA线程在运行,它将会出错。另一种情况是,如果OLE32.dll在DllMain DLL_THREAD_DETACH上检测到此情况,并进行必要的清理,从而在后续代理方法调用中稍早出错。

您不能存储未编组的接口指针,因为如果这样做,从其他公寓调用其方法很可能会造成麻烦,例如: STA对象可能尚未准备好进行多线程处理,或者可能无法访问线程本地存储,并且MTA对象可能尚未准备好进行Windows消息循环或重入。

请注意,可能存在多个STA,并且由于COM本身没有STA对象切换其公寓,只有通过返回直接的非编组接口指针。因此,当STA死亡时,其对象不被采用&#34;由现有的或未来的STA,甚至主要的STA(第一个STA)或默认的STA(由COM本身创建的必需的一个),可能是相同的。

此外,在创建MTA之后,如果在第一次使用COM时没有显式初始化,则每个新线程都隐式属于MTA。但是,这样的线程不会让MTA保持活力。


P.S:我从您的评论中读到,您的MTA对象实际上是一个自由线程对象。由于自由线程对象绕过进程中的编组,因此它们属于实际创建它们的任何公寓,它的方法在当前公寓中运行,并且它们必须为由于来自STA的跨公寓,非阻塞调用,在模态Windows消息循环中进行多线程和重入。