過去我已經使用多線程完成了很多工作,但我對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