は、私は、スレッドセーフ機能スレッドセーフな並列RNG()
rand_r
で円周率の計算のこのバージョンを使用しかし、これを実行しているときに、遅くなることが表示されます(と答えが間違っています)プログラムは、スレッドセーフではない
rand()
を使用するシーケンシャルプログラムと比較して並列に実行されます。この使用方法はスレッドセーフではないようです。しかし、なぜ私はスレッドセーフなPRNGについての多くの質問を読んでいて、rand_rは十分安全であるべきだということを知っていたので、なぜわかりません。
#include <iostream>
#include <random>
#include <ctime>
#include "omp.h"
#include <stdlib.h>
using namespace std;
unsigned seed;
int main()
{
double start = time(0);
int i, n, N;
double x, y;
N = 1<<30;
n = 0;
double pi;
#pragma omp threadprivate(seed)
#pragma omp parallel private(x, y) reduction(+:n)
{
for (i = 0; i < N; i++) {
seed = 25234 + 17 * omp_get_thread_num();
x = rand_r(&seed)/(double) RAND_MAX;
y = rand_r(&seed)/(double) RAND_MAX;
if (x*x + y*y <= 1)
n++;
}
}
pi = 4. * n/(double) (N);
cout << pi << endl;
double stop = time(0);
cout << (stop - start) << endl;
return 0;
}
P.S.ちなみに、魔法の数字は何ですか?
seed = 25234 + 17 * omp_get_thread_num();
?私はいくつかの答えからそれらを盗んだ。
EDIT: Gillesのコメントが私を助けました。解決方法は次のとおりです。 1. forループとシードの初期化を切り替えるには 2.
変更されたコードのための#pragma OMPを追加するには、問題が解決され
#pragma omp parallel private(x, y, seed)
{
seed = 25234 + 17 * omp_get_thread_num();
#pragma omp for reduction(+:n)
for (int i = 0; i < N; i++) {
x = (double) rand_r(&seed)/(double) RAND_MAX;
y = (double) rand_r(&seed)/(double) RAND_MAX;
if (x*x + y*y <= 1)
n++;
}
}
を読み込みます。
答えが間違っているとはどういう意味ですか? rand_rがスレッドごとに別々のシーケンスをサポートすることを期待していますか?確かに、これらのシーケンスの1つ以上は、同じジェネレータの単一のスレッド呼び出しと一致しません。 2つのスレッドが同じシーケンスに入った場合、真のPRNGは「間違っている」と考えられますが、非並列ジェネレータを使用してショートカットを作成すると、そのような保証はありません。 – tim18
@ tim18 "答えが間違っている"とは、Piの結果値が3.14ではない(ただし、rand()で逐次プログラムを使用する場合は3.14)。はい、スレッドの数に応じてシードを使用しているので、スレッドごとに別々のシーケンスが必要です。または、私は何かを逃していますか?... – newt
はい、あなたは何かが間違っています:ループの各反復でシードを初期化してはいけません。 ATMのやり方で、まったく同じ「ランダム」番号を繰り返し生成します。 – Gilles