2015-10-17 65 views
3

考慮以下最小的C代碼示例。在編譯和執行export OMP_NUM_THREADS=4 && gcc -fopenmp minimal.c && ./a.out(Debian 8上的GCC 4.9.2)時,這會在我的機器上生成5行rho=100(有時也是200或400)。所有五條印刷線的預期輸出當然是rho=400爲什麼下面的OpenMP程序不能減少我的變量?

如果我在// MARKER處插入更多代碼或在此處放置障礙物,程序更可能產生正確的結果。但即使有另一個障礙,它有時也會失敗,我的計劃也是如此。所以這個問題似乎是a進入還原循環時未正確初始化。

OpenMP 4.0.0 manual甚至在第55頁的狀態在循環結構的末尾存在隱式屏障,除非指定了nowait子句。所以a應該在這一點上設置。這裏出了什麼問題?我錯過了什麼嗎?

#include <stdio.h> 
#ifdef _OPENMP 
#include <omp.h> 
#define ID omp_get_thread_num() 
#else 
#define ID 0 
#endif 

double a[100]; 

int main(int argc, char *argv[]) { 
    int i; 
    double rho; 
    #pragma omp parallel 
    { 
     #pragma omp for 
     for (i = 0; i < 100; i++) { 
      a[i] = 2; 
     } 
     // MARKER 
     rho = 0.0; 
     #pragma omp for reduction(+: rho) 
     for (i = 0; i < 100; i++) { 
      rho += ((a[i])*(a[i])); 
     } 
     fprintf(stderr, "[%d] rho=%f\n", ID, rho); 
    } 
    fprintf(stderr, "[%d] rho=%f\n", ID, rho); 
    return 0; 
} 
+0

[鐺似乎產生正確的結果](http://melpon.org/ wandbox/permlink/Jmkv5VcXKQJ4sMNN) –

+0

修改'rho'時你需要一個互斥嗎? – donjuedo

+0

我不這麼認爲。手冊的第167頁說:* reduction條款指定了一個縮減標識符和一個或多個列表項。對於每個列表項,在每個隱式任務或SIMD通道中創建一個私有副本,並使用還原標識符的初始化程序值進行初始化。在區域結束後,使用與縮減標識符相關聯的組合器,使用私人副本的值更新原始列表項。* – valyron

回答

3

確定我已經得到了答案,但我汗得到它...

這是一個競爭狀態,由於這樣的事實,rho是共享的,你初始化它的並行區域內這樣rho = 0.0;

要麼初始化它的平行區域的外側,或者使用#pragma omp single右之前將修復代碼...

+0

我認爲你是對的,雖然這很難驗證。至少這個問題在移動'rho = 0.0;'時消失,或者在該語句之後放置障礙物。所以,接受。時間爲第二輪:http://stackoverflow.com/questions/33190809/why-does-openmp-fail-to-sum-these-numbers – valyron

+0

良好的觀察!如果OP沒有改變她/他的標量代碼,而只是使用了'#pragma omp parallel for'兩次,這不會發生。 –

+0

是的,你是對的。我這樣做是因爲我認爲它更高效,因爲程序只需要分支一次。很可能是錯誤的,因爲只有一次創建線程並在沒有工作需要完成的情況下進行睡眠,並且因爲編譯器優化。 – valyron

相關問題