2012-04-07 88 views
1

我有一個嵌套的循環:(L和A完全定義輸入)連續和並行版本會產生不同的結果 - 爲什麼?

#pragma omp parallel for schedule(guided) shared(L,A) \ 
    reduction(+:dummy) 
    for (i=k+1;i<row;i++){ 
      for (n=0;n<k;n++){ 
       #pragma omp atomic 
       dummy += L[i][n]*L[k][n]; 
       L[i][k] = (A[i][k] - dummy)/L[k][k]; 
      } 
      dummy = 0; 
    } 

而其串行版本:

for (i=k+1;i<row;i++){ 
      for (n=0;n<k;n++){ 
       dummy += L[i][n]*L[k][n]; 
       L[i][k] = (A[i][k] - dummy)/L[k][k]; 
      } 
      dummy = 0; 
    } 

他們都得到不同的結果。並行版本比順序版本慢得多。

什麼可能導致問題?

編輯:

爲了擺脫引起的原子指令的問題,我修改了代碼如下:

#pragma omp parallel for schedule(guided) shared(L,A) \ 
    private(i) 
    for (i=k+1;i<row;i++){ 
     double dummyy = 0; 
     for (n=0;n<k;n++){ 
      dummyy += L[i][n]*L[k][n]; 
      L[i][k] = (A[i][k] - dummyy)/L[k][k]; 
     } 
    } 

但它也沒有工作出了問題。結果仍然不同。

+0

如果您在浮點數操作,請閱讀此http://計算器.com/a/8991640/893693 – inf 2012-04-07 08:21:46

回答

1

結果的差異來自線程間共享的內部循環變量n,因爲它是在omp編譯指示之外定義的。

澄清: 循環變量n應OMP編譯內部聲明,因爲它應該是線程專用的,例如for (int n = 0;.....)

+0

完全解決了我的問題。謝謝! – 2012-04-07 10:54:20

+0

@Lubo,那麼正確的方法是什麼? – 2013-09-28 13:12:20

2

我對OpenMP並不是很熟悉,但在我看來,您的計算並不依賴於順序。也就是說,內循環中的結果寫入L[i][k],其中ik是內循環的不變量。這意味着在內循環期間相同的值被覆蓋k次,導致競爭條件。

此外,dummy似乎在不同的線程之間共享,所以也可能存在競爭條件,除非您的編譯指示參數以某種方式阻止它。

總而言之,對於我來說,如果您希望獲得與順序執行相同的結果,則內部循環中的計算必須以相同的順序執行。因此只有外部環路可以並行化。

+0

我也考慮過這個問題。但是使用這些編譯指令,只有外部循環應該被並行化。但顯然,線程內部正在發生其他事情,所以結果並不相同。 – 2012-04-07 08:45:13

2

在您的並行版本中,您插入了不必要的(可能有害的)原子指令。一旦你聲明dummy是一個縮減變量,OpenMP負責停止干擾縮減的線程。我認爲這個不必要的指令的主要影響是減慢你的代碼,很多。

我看到你有另一個解決你的結果錯誤的答案。但我注意到,在每個外循環迭代結束時,您似乎將dummy設置爲0,如果您嘗試將它用作某種累加器,這似乎很奇怪,這就是還原子句所暗示的內容。也許你想在內循環中減少到dummy

如果您在還原時遇到問題read this

+0

我實際上想要內循環在每個線程中順序運行。我現在假設內部循環也是分佈式的 - 否則我不會遇到這些問題。 我稍微修改了代碼。我編輯過,以便您可以看到修改。 – 2012-04-07 08:50:14

相關問題