2015-10-18 149 views
2

我想讓這個程序運行多個線程。爲什麼OpenMP程序每次都給我不同的答案?

#include <stdio.h> 
#include <time.h> 
#include <omp.h> 

#define NUM_THREADS 4 
static long num_steps = 1000000000; 

int main() 
{ 
    int i; 
    double x, pi, sum = 0.0; 
    double step = 1.0/(double)num_steps; 

    clock_t start = clock(), diff; 
    #pragma omp parallel for num_threads(NUM_THREADS) reduction (+:sum) 
    for (i = 0; i < num_steps; i++) 
    { 
    x = (i+0.5)*step; 
    sum += 4.0/(1.0 + x*x); 
    } 
    #pragma omp ordered 
    pi = step*sum; 
    printf("pi = %.15f\n %d iterations\n", pi, num_steps); 

    diff = clock() - start; 
    int msec = diff * 1000/CLOCKS_PER_SEC; 
    printf("Time taken %d seconds %d milliseconds", msec/1000, msec%1000); 

    return 0; 
} 

加入#pragma omp parallel for num_threads(NUM_THREADS) reduction (+:sum)。在for循環之後我也有#pragma omp ordered,我不認爲我真的需要它,因爲沒有線程應該繼續,直到所有線程都完成for循環。它是否正確?這也是爲什麼我僅僅將性能作爲一個單線程程序運行的第二次增長的原因?這是6秒,而我的7秒。

我不能回答的是,爲什麼本計劃給我一個不同的答案PI我每次運行時的事情嗎?

+0

我在vs2015測試程序,它給了我pi的每一次 – HDJEMAI

+0

很奇怪的值相同。只是複製並粘貼它並跑了兩次。第一次我得到3.141737761473218,然後第二次得到3.141576654805244。如果這意味着什麼,我在Windows上。也許我應該在Linux中嘗試它。 – rangeme

+0

我得到所有的時間3.141592653589971女巫看起來不錯 – HDJEMAI

回答

2

您的問題來自於您忘記聲明xprivate。 如果你改變你的OpenMP指令爲:

#pragma omp parallel for num_threads(NUM_THREADS) reduction(+:sum) private(x) 

你的代碼變得有效。

然而,仍然有在這裏兩個問題:

  1. #pragma omp ordered是沒有意義的,因爲你不是爲parallel區域。你應該刪除它。
  2. 使用clock()在多線程代碼的測量時間是危險的,而不是因爲功能不是線程安全的,但由於它返回CPU時間當前線程的兒童中,沒有已用時間。因此,您經常會發現結果幾乎與OpenMP激活和未激活的結果相同,並且人們想知道爲什麼他們的代碼不會暴露任何加速。因此除非您有充分的理由使用clock(),否則請使用omp_get_wtime()
+2

請注意,OP是使用Windows。使用MSVC和MinGW(但不是MinGW-w64)使用'clock()'的Microsoft C運行時庫返回掛牆時間。但我同意'omp_get_wtime()'是最好的一般用法。 –

+0

正是因爲這個原因,使用'default(none)'是一個好主意。 – Richard

3
從錯誤

除了指出的吉爾斯,這裏有一個更根本的問題。整個並行線程

減少不一定是確定性的。每個線程貢獻的組合順序可隨每次執行代碼而改變。如果你不知道爲什麼那麼重要,請去閱讀「What Every Computer Scientist Should Know About Floating-Point Arithmetic

如果你還沒有得到的觀點,但考慮三個線程做一個十進制算術機的總和減少,支持三位數的精確。 假設我們正在累積集合(100,-100,0.1),如果我們按順序添加它們,我們將有100-100 = 0 + 0.1 = 0.1,但是如果我們按順序將它們相加(100,0.1, -100),我們會得到100 + 0.1 = 100(三級顯著數字,切記!)-100 == 0

如果您在使用英特爾編譯器,還有可以設置爲請求確定性的環境變量減少(KMP_DETERMINISTIC_REDUCTION),但是隻有在使用相同數量的線程時纔會執行確定性。它不會在具有不同數量的線程的運行之間強制執行它。 (這樣做需要強制執行一個線程貢獻累積的命令,這需要不同的代碼生成和一些線程間同步)。

相關問題