考虑以下情况:
此代码由线程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对象的状态是什么。
答案 0 :(得分:0)
它取决于COM对象本身和创建它的线程的线程模型。
如果对象是单元线程的,它将存在于自己的STA中。如果STA线程创建对象,则线程在与对象相同的STA中运行,并接收指向该对象的直接指针。如果MTA线程创建对象,则创建新STA并且线程接收STA中对象的代理。在任何一种情况下,如果其他线程想要访问它,则必须对该对象进行编组。
如果对象是多线程的,它将存在于MTA中。如果STA线程创建对象,则线程接收MTA中对象的代理。如果MTA线程创建对象,它将接收指向该对象的直接指针。该对象可以由其他MTA线程直接访问,但如果由STA线程访问,则必须进行编组。
如果对象是自由线程的,则如果由STA线程创建,它将存在于STA中,并且如果由MTA线程创建,它将存在于MTA中。然后适用上述规则。
在MSDN上详细讨论了这个主题:
Processes, Threads, and Apartments
答案 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消息循环中进行多线程和重入。