[英]Openmp multithreaded code giving different answer when using multiple threads
我有以下帶有openmp
多線程的蒙特卡羅代碼
int main()
{
std::uniform_int_distribution<int> dir(0, 1);
std::uniform_int_distribution<int> xyz(0, 2);
std::uniform_real_distribution<double> angle(0,360);
mt19937 gen{0};
auto M = 20;
long double sum = 0;
auto num_trials = 10000;
// omp_set_num_threads(12);
#pragma omp parallel
{
double loc_sum = 0.0;
#pragma omp for
for(int i = 0; i < num_trials; ++i)
{
double x = 0;
double y = 0;
double z = 0;
double r = 0;
auto N = 0;
while(r < M)
{
auto d = dir(gen);
auto p = xyz(gen);
if(p == 0)
{
x += (d == 1) ? -1 : 1;
}
else if(p == 1)
{
y += (d == 1) ? -1 : 1;
}
else
{
z += (d == 1) ? -1 : 1;
}
r = std::sqrt(x * x + y * y + z * z);
++N;
}
loc_sum += N;
}
#pragma omp critical
sum += loc_sum;
}
}
串行執行和多線程執行的變量sum
完全不同。 由於對隨機均勻分布的調用,我預計會有輕微的差異,但我觀察到的差異太大,不可能是由於隨機性,我懷疑我的多線程代碼中存在錯誤。
此代碼中是否存在影響sum
競爭條件或數據競爭?
問題是您在調用生成器( dir
和xyz
)時沒有鎖定它們。 您還可以在不鎖定的情況下使用 PRNG ( gen
)。
這些調用都不是原子的,因為默認情況下實現它們會使單線程代碼比它需要的慢。
使用#pragma omp critical
標記生成d
和p
的行應該可以解決問題。
如果您不想要臨界區,則需要在每個線程中使用單獨的dir
、 xyz
和gen
對象。 生成器( dir
和xyz
)可以簡單地復制。 PRNG ( gen
) 應該在每個線程中正確初始化,否則你最終會在每個線程中得到具有完全相同狀態的 PNG。 例如:
std::random_device rd; /* Outside the parallel section. */
// Code below once per thread.
/* Initialization of the PRNG calls std::random_device::operator() which
* needs a lock around it when called in parallel. */
std::mt199937 gen;
#pragma omp critical
{
gen.seed(rd());
}
// for-loop starts here.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.