过去我已经使用多线程完成了很多工作,但我对COM还是比较陌生的。无论如何,这是我的问题:安全地同步COM线程
我创建一个工作线程,它注册为一个STA,并创建一个COM对象。然后工作者线程和主线程尝试相互通信。使用CoMarshalInterThreadInterfaceInStream
和CoGetInterfaceAndReleaseStream
,我可以让线程调用其他线程中COM对象的方法。
这里的工作线程的样子:
void workerThread()
{
CoInitialize(NULL);
MyLib::IFooPtr foo = ...; // create my COM object
// Marshall it so the main thread can talk to it
HRESULT hr = CoMarshalInterThreadInterfaceInStream(foo.GetIID(),
foo.GetInterfacePtr(),
&m_stream);
if (FAILED(hr)) {
// handle failure
}
// begin message loop, to keep this STA alive
MSG msg;
BOOL bRet;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1) break;
DispatchMessage(&msg);
}
}
在主线程:
// launch the thread
m_worker = boost::thread (&workerThread);
// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));
这将创建对象(这需要一段时间来初始化),并允许主线程与之交谈,一切都与COM公寓的东西正确同步。据我所知,读取MSDN,这似乎是正确的做事方式。现在主线程可以使用它的代理来调用我的COM对象上的方法,并且工作线程将通过消息队列接收这些调用,并正确调度它们。
但是,同步这些线程呢?
很明显,在这种情况下,我希望主线程等待调用CoGetInterfaceAndReleaseStream
,直到工作线程通过CoMarshalInterThreadInterfaceInStream
创建该流为止。但我怎么能安全地做到这一点?
从MSDN,我应该用什么样MsgWaitForMultipleObjects
,所以我可以等待my_condition OR new_message_arrived,然后我可以这样做:
// verbatim from msdn
while (TRUE)
{
// wait for the event and for messages
DWORD dwReturn = ::MsgWaitForMultipleObjects(1,
&m_hDoneLoading, FALSE, INFINITE, QS_ALLINPUT);
// this thread has been reawakened. Determine why
// and handle appropriately.
if (dwReturn == WAIT_OBJECT_0)
// our event happened.
break ;
else if (dwReturn == WAIT_OBJECT_0 + 1)
{
// handle windows messages to maintain
// client liveness
MSG msg ;
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
::DispatchMessage(&msg) ;
}
}
但我怎么混boost::thread.join()
和boost::condition.wait()
与MsgWaitForMultipleObjects
?这甚至是可能的,还是我必须做其他事情来避免竞争状况?
不,我不知道这是我想要的。我正在处理遗留的单线程应用程序,试图通过添加线程来缩短启动时间。我意识到我正在为一般运行时间交易启动时间。我希望最终能够将它交给MTA,但将STA用作开发的中间步骤。 – Tim 2011-04-18 22:12:11
如果已经启动了N个线程,每个线程创建一个STA对象,那么每创建一个线程并将接口封装到流中时,递减一个计数器(InterlockedDecrement)。将其递减为0的是最后一个,并且可以发信号通知事件。主线程处于空闲状态,等待这个事件,当它被发信号时,它可以安全地继续前进并解组所有流。这对遗留应用逻辑的影响最小,同时允许并行创建N个COM对象。 – 2011-04-18 22:20:52
你能举一个例子吗?我不清楚如何使用PostThreadMessage和MsgWaitForMultipleObjects。 – Tim 2011-04-18 22:27:40