2010-02-21 144 views
10

我有一個Windows窗體與報表模式下的ListView。對於視圖中的每個項目,我需要執行長時間運行的操作,其結果是一個數字。什麼是MsgWaitForMultipleObjects的C#等價物?

我在原生win32中執行此操作的方式是爲每個項目創建一個工作線程(當然,我不會創建無限數量的線程),然後在線程句柄數組上創建MsgWaitForMultipleObjects()。隨着每個計算完成,線程信號和主UI線程喚醒並更新。與此同時,我們抽取消息以使UI線程保持響應。

任何人都可以提供一個如何在C#中工作的例子嗎?我查看了Monitor對象,而且它看起來並不是我想要的 - 或者是在阻塞時抽取消息?

謝謝。

編輯:似乎WaitHandler.WaitAny()可能實際上泵送消息。請參閱cbrumme's treatise關於CLR中的信息抽取。

+0

你說得對,Monitor不會收集消息。 WaitHandle可能是一個更好的地方,但是我找不到一個WaitHandle方法來提取消息。 – itowlson 2010-02-21 23:45:35

+0

是的,我也看到了。這不是要求我能夠等待多個對象。我會等待一個事件或其他事情......我只是不想阻止用戶界面。我發現的所有樣本都會「睡覺(100)」或其他東西來強制上下文切換,這非常令人傷心。 – 2010-02-21 23:47:26

+0

我想問題是,在WinForms中,消息循環並不明確。所以你不能直接做一個MsgWaitX,你需要的東西會引發一個事件。例如,將每個子任務作爲BackgroundWorker運行(並忘記同步基元)。 – itowlson 2010-02-22 00:13:49

回答

2

長期運行的活動對象,我認爲是您的案例中的最佳選擇。主線程調用代理(活動對象的)。代理將呼叫方法轉換爲消息,並且此消息將進入隊列。代理向調用者返回未來對象(它是對未來結果的引用)。調度員一個接一個地出隊消息,並且在其他線程(工作線程)中執行你的任務。當工作線程完成任務時,它會更新未來對象的結果或調用回調方法(例如,更新UI).Dispather可以有許多工作線程同時執行更多任務。

您可以看到有關長時間運行的活動對象模式的此article(帶有示例)。

+0

請提供一些信息,而不僅僅是信息的鏈接。 – 2010-02-22 00:06:52

+0

嗯,這真的好像很多代碼來解決這樣一個簡單的問題。我的意思是,如果我願意的話,我總是可以捏住我自己的COM對象。如果C#框架還不夠成熟,那麼我可以重新編寫win32代碼。雖然我不得不相信他們是一個簡單的方法來做到這一點。 – 2010-02-22 18:01:29

+0

是的,你是對的。這是來自MSDN的示例: connection1.Open(); SqlCommand command1 = new SqlCommand(commandText1,connection1); IAsyncResult result1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; connection2.Open(); \t \t ... \t \t 的WaitHandle [] waitHandles = { waitHandle1,waitHandle2,waitHandle3 }; \t \t bool result = WaitHandle.WaitAll(waitHandles,60000,false); – garik 2010-02-22 20:44:48

2

你的主線程是否創建了一個管理線程。你可以使用這個BackgroundWorker。此管理器線程爲ListView中的每個項目啓動一個工作線程。這將允許您的用戶界面在後臺線程正在處理時不停地響應用戶輸入。

現在,問題是如何等待每個工作線程完成。不幸的是,我一直無法找到一種方法來獲得System.Threading.Thread對象的線程句柄。我並不是說沒有辦法做到這一點;我只是沒有找到一個。另一個複雜的方面是,System.Threading.Thread類是密封的,所以我們不能從它得到提供某種'處理'。

這是我用的地方ManualResetEvent

假設每個工作線程只是一個ThreadPool線程。管理BackgroundWorker爲ListView中的每個項目創建一個ManualResetEvent對象。當BackgroundWorker啓動每個ThreadPool線程時,將ManualResetEvent作爲參數傳遞給QueueUserWorkItem function。然後,在每個ThreadPool線程退出之前,設置ManualResetEvent對象。

然後BackgroundWorker線程可以將所有的ManualResetEvent對象放在一個數組中,並使用WaitHandle.WaitXXX functions等待該數組。隨着每個線程完成,您可以使用BackgroundWorker的事件來更新UI,或者您可以使用Control.Invoke()技術更新UI(請參閱Marc Gravell的回答here)。

希望這會有所幫助。

+0

這似乎是一個合理的方法,如果我無法弄清楚消息等待。我覺得很難相信沒有一個。我會更新線程,如果我找到了一些東西。 – 2010-02-22 17:59:25