2011-10-12 38 views
2

我有一個庫,其中包含一個IJobMaker實體,該實體創建一定數量的IJob對象,以便在其自己管理的線程上運行。 要跟蹤每個IJob的進展情況,我在每個工作中都實施了觀察員模式,並使用IProgressObserver。當我想彙報總體進展時,就會遇到困難。多線程任務總體進度報告的設計模式

對我來說,理想的做法是讓IProgressOverserver.ReportProgress(float jobProgress, float overallProgress報告工作和整體進度。 IJobMaker可以瞭解整個工作的每個工作部分,並以某種方式收集每個人的報告。

兩個主要的問題出現了:

  1. 同步機制?例如,在IJobMaker內部保留一個互斥體可能會損害性能,因爲IProgressOverserver.ReportProgress被調用了很多,互斥體可能會導致上下文切換,而不會導致上下文切換。 InterlockedIncrement看起來是個不錯的選擇,但由於沒有這樣的浮點函數,所以我將被迫以整數增量報告進度。 (我想遠離C++ 0x功能或Boost)

  2. 設計模式? IJob的進展是從最深的算法中報告的。我需要每一份這樣的報告都與中央實體進行溝通,以便總體進度計算,並請撥打IJob中的IProgressObserver.ReportProgress方法。

回答

0

首先,在這種情況下使用浮動是非常糟糕的做法。使用整數。

還有一個建議。您可以使用分段 - 通過一個互斥/原子(一個分段)僅同步幾個線程。然後收集所有細分市場。

此外,還有良好的開端環顧四周高度並行算法:http://www.1024cores.net/home/lock-free-algorithms

UDPATE 有例子的問題與浮動

#include <iostream> 
using namespace std; 
int main() { 
    float f = 0; 
    for(int i=0; i<100000-98; ++i) 
    { 
     f += 0.00001; 
    } 
    cout << f << endl; 
} 

所以,如果你有100個就業機會,每個1000步,你會在98之前得到1.0結果,比你想象的要早。

+0

你能詳細說明爲什麼它不好使用浮動?另外,我不確定我是否明白你的分類意思。我如何只同步幾個線程? – Leo

+0

花車設計用於各種值。我不認爲你在'1E-200' - '1E200'之間有進展。對於你的情況你可以有'AtomicInteger'並做精確的計算,但是我從來沒有聽說過'AtomicFloat'。是的,你可以將少數幾個線段分組。它允許在單個互斥鎖上同步更少的線程。 – kan

+0

但我必須同步這些細分才能得到最終答案。也許它會起作用,如果我允許一些'IJob'的進展,直到用戶獲得整體進展報告爲止。然而,既然我想要立即回答,我不得不在分段之間和分段之間進行同步,這似乎同樣有害。關於浮點數,我可以有0到1之間的範圍。整數也是很寬的範圍,但只使用一個子範圍。 – Leo

1

一對夫婦對穿線前的建議:

  1. 不報告的每一個進步哪怕一丁點。一旦進行了某個預定義的進度量,或者經過了某個預定義的時間量,或者子作業已經完成,則僅向主線程報告。這可以大大減少同步的數量。
  2. 如果你實現了#1,互斥鎖可能工作得很好。
  3. 如果互斥體結果太貴,您可以使用原子整數變量來報告進度:只需將值從「無進度」縮放到「全部完成」到0 ... INT_MAX

就設計API而言,應該不難想出一些合理的東西。我的一般建議是不要過度使用它。

+0

我會盡可能「大致」報告,但我仍然相信使用鎖可能會對性能造成不良影響。無論我的報告多麼遙遠,我總是可以將事情擴展到瓶頸。 (擁有大量的線程和'IJob')這個庫應該能夠擴展到10個核心。 – Leo