我一直在玩一個愛好項目的DataBus類型的設計,我遇到了一個問題。後端組件需要通知UI發生了什麼事。我的總線實現與發送者同步傳遞消息。換句話說,當你調用Send()
時,該方法會阻塞,直到所有的處理程序調用。 (這使得調用者可以使用堆棧內存管理來處理事件對象。)WinForm樣式Invoke()in unmanaged C++
但是,請考慮事件處理程序更新GUI以響應事件的情況。如果處理程序被調用,並且消息發送者駐留在另一個線程上,則由於Win32的GUI元素具有線程相關性,處理程序無法更新GUI。 .NET等更多動態平臺允許您通過調用特殊的Invoke()方法將方法調用(和參數)移動到UI線程來處理此問題。我猜他們使用.NET停放窗口或類似的東西來做這些事情。
一種病態的好奇心誕生了:即使我們限制了問題的範圍,我們可以用C++來做到嗎?我們可以比現有的解決方案更好嗎?我知道Qt的功能與moveToThread()
功能類似。
通過更好,我會提到,我特別想避免以下形式的代碼:
if(! this->IsUIThread())
{
Invoke(MainWindowPresenter::OnTracksAdded, e);
return;
}
是在每個用戶界面方法的頂部。在處理這個問題時,這種舞蹈在WinForms中很常見。我認爲這種關注應該與領域特定的代碼和一個用於處理它的包裝器對象隔離。
我實現由:
DeferredFunction - 仿函數存儲在一個FastDelegate目標方法,而深拷貝單個事件的說法。這是通過線程邊界發送的對象。
UIEventHandler - 負責從公共汽車調度單個事件。當調用
Execute()
方法時,它將檢查線程ID。如果它與UI線程ID(在構建時設置)不匹配,則使用實例,方法和事件參數在堆上分配DeferredFunction。指向它的指針通過PostThreadMessage()
發送到UI線程。最後,鉤子函數用於線程的消息泵用於調用DeferredFunction並取消分配它。或者,我可以使用消息循環過濾器,因爲我的UI框架(WTL)支持它們。
最終,這是一個好主意嗎?整個消息掛鉤的事情讓我很沮喪。目的當然是高貴的,但是我應該知道有什麼缺陷?還是有更簡單的方法來做到這一點?
你爲什麼不在Reflector中打開Invoke,看看他們是如何做到的? :) – 2010-04-13 03:17:35
你知道嗎,我從來沒有想過...明天我會給它看看。 :) – 2010-04-13 03:20:28