2012-12-22 74 views
2

我也遇到過需要在我的Windows使用多線程形成用C++ GUI應用程序。從我對這個話題的研究看來,後臺工作者線程是我爲了達到目的而走的路。根據示例代碼,我有在多線程和後臺工作線程的一些問題,在Windows窗體

System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) 
{ 
    BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender); 
    e->Result = SomeCPUHungryFunction(safe_cast<Int32>(e->Argument), worker, e); 
} 

但也有幾件事情,我需要獲得連勝,找出

  • 後臺工作線程將讓我的多線程生活更輕鬆?
  • 爲什麼我需要e->結果?
  • 傳遞給backgroundWorker1_DoWork函數的參數是什麼?
  • 參數safe_cast(e-> Argument)的用途是什麼?
  • 我應該在CPUHungryFunction()中做什麼?
  • 如果我的CPUHungryFunction()有一個無限循環的while循環呢?
  • 我有工作線程獲取處理器時間的控制權嗎?
  • 可以更具體地控制循環在設定的時間段內循環的次數嗎?當我只需要每秒循環30次時,我不想使用cpu每秒循環1000次。 *是否需要控制更新GUI的速率?
+0

我剛剛在我的帖子中添加了另一個關於safe_cast(e-> Argument)的簡短問題。 – workdamnit

回答

3

將後臺工作線程使我的多線程生活更輕鬆?

是的,非常非常。它可以幫助您處理您無法從工作線程更新UI的事實。特別是ProgressChanged事件使您可以顯示進度和RunWorkerCompleted事件,您可以使用工作線程的結果,而你不必處理跨線程問題來更新UI。

爲什麼我需要e->結果?

將您所做的工作結果傳回給UI線程。您可以在RunWorkerCompleted事件處理程序e-> Result屬性中返回值。然後從中更新UI的結果。

傳遞給函數的參數是什麼?

要告訴工作線程該怎麼做,它是可選的。否則與將參數傳遞給任何方法相同,因爲您沒有選擇參數,所以更加尷尬。您通常會從您的用戶界面傳遞某種價值,例如,如果您需要傳遞多個值,請使用一個輔助類。總是傾向於嘗試在工作人員中獲取UI值,這非常麻煩。

我應該在CPUHungryFunction()中做些什麼?

當然會燒燬CPU週期。或者通常做一些需要很長時間的事情,比如dbase查詢。它不會刻錄CPU週期,但需要很長時間才能讓UI線程在等待結果時死機。粗略地說,每當你需要做一些事情需要一秒以上的時間時,你應該在工作者線程而不是UI線程上執行它。

如果我的CPUHungryFunction()有一個無限循環的while循環會怎麼樣?

然後,你的工人永遠不會完成,永遠不會產生結果。這可能很有用,但並不常見。您通常不會爲此使用BGW,而只是將其IsBackground屬性設置爲true的常規線程。

我是否可以控制工作線程獲取的處理器時間?

你有一些通過調用Thread.Sleep()人爲地減慢它。這不是一件常見的事情,啓動一個工作線程的關鍵是做工作。睡眠的線程以非生產性的方式使用昂貴的資源。

可以更具體地控制循環在設定的時間段內循環的次數嗎?當我只需要每秒循環30次時,我不想使用cpu每秒循環1000次。

和上面一樣,你必須睡覺。通過執行循環30次,然後休眠一秒鐘來完成。

是否需要控制更新GUI的速率?

是的,這非常重要。 ReportProgress()可以是一個消防軟件,每秒產生數千次UI更新。當UI線程無法跟上這個速度時,你可以很容易地解決這個問題。您會注意到,UI線程會停止處理日常工作,例如繪製UI和響應輸入。因爲它不得不處理另一個調用請求來運行ProgressChanged事件處理程序。副作用是用戶界面看起來凍結,你有準確的問題,你正試圖解決一個工人。它實際上並沒有被凍結,它只是看起來這樣,它仍然在運行事件處理程序。但你的用戶不會看到差異。

有一點需要記住的是ReportProgress()只需要保持人眼快樂。無法看到每秒發生的次數超過20次的更新。除此之外,它變成了一種難以理解的模糊。所以不要浪費時間在UI更新上,反正無用。您將自動避免消防水帶問題。調整更新速度是你必須編程的東西,它不是內置在BGW中的。

+0

+1非常非常全面的回答 – Steve

+0

感謝漢斯,這些答案真的很有幫助。 – workdamnit

1

我會盡量回答您的問題質疑

  1. DoWork的是一種無效的方法(和需要如此)。此外,DoWork在與調用線程不同的線程中執行 ,因此您需要有一個 的方式才能將某些內容返回給調用線程。該E->結果 參數將被傳遞給內部 的RunWorkerCompleted事件RunWorkerCompletedEventArgs
  2. 發件人的說法是,你可以使用 引發事件的UI線程BackgroundWorker的本身,DoWorkEventArgs最終 包含從傳遞的參數調用線程無論你需要做的(誰擁有 一個叫RunWorkerAsync(Object)
  3. 。關注無法從DoWork線程訪問的用戶界面 元素。通常情況下,一個 計算所做的工作率和更新用戶界面(進度 酒吧或一些相似),並調用ReportProgress與 UI線程進行通信。 (需要有WorkerReportProgress屬性設置爲 真)
  4. 沒有無限期運行。你可以隨時拔掉電源線。 說真的,這只是另一個線程,操作系統會照顧它,當你的應用程序結束時,它會銷燬所有的東西。
  5. 不知道你是什麼意思這一點,但它可能與 下一個問題
  6. 您可以使用Thread.sleep代碼或方法的Thread.join一個循環之後,釋放 CPU時間。睡眠的確切時間應罰款 取決於你在做什麼,目前 系統的工作量和處理器的原始速度調整

請參閱MSDN文檔上BackgroundWorkerThread

+0

用於回答所有問題的+1,但也許你應該只是提到Thread.Join提供downvote :) –

+0

@MartinJames,你能指點我對Thread.Join的一些討論缺點嗎?真的從未使用它,只是參考MSDN上有關消息泵的註釋。 – Steve

+0

謝謝史蒂夫,這些答案是我正在尋找的答案。 – workdamnit