2017-02-10 3 views
13

私は少しこのようになりますいくつかのコードがあります。スレッドセーフ:: random_device

std::random_device rd; 

#pragma omp parallel 
{ 
    std::mt19937 gen(rd()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

を私はいくつかの質問があります:

  • std::random_device、スレッドセーフですか?つまり、複数のスレッドが同時に呼び出すときに何か役に立たないことをしていますか?
  • これは一般的には良い考えですか?乱数ストリームの重複が心配すべきでしょうか?
  • 私は欲しいものを達成する良い方法がありますか(各スレッドの独立した乱数ストリーム - 私は現時点で再現性についてあまり心配していません)?

std::random_deviceの動作に何らかの違いがある場合は、主にWindowsで動作していますが、LinuxとOSXでも同様に動作するようにしたいと思います。

+0

'std :: random_device'を使うのではなく、特定のシードを使って再現性を達成できます。 – Galik

+0

'random_device'がブロックされている可能性があります。あなたが望むものが並列性であれば、そのように使うことはそれほど重要ではありません。 'random_device'でシードされたグローバルPRNGを使って' mt19937'をシードすることができます(ただし、明示的なロックが必要です)。 – sbabbi

答えて

3

注:この答えは、一般的にGCC Linuxが、OpenMP上で動作しますがthread_localなどの機能が動作しない場合がありますので、stdスレッドモデルとの相互運用に保証するものではありません。

は、私はおそらくPRNGスレッドローカル静的になるだろうし、それを初期化する(それは私を聞かせている場合、この回答を削除します)std::random_device一時的:

#pragma omp parallel 
{ 
    // different gen for each thread 
    thread_local static std::mt19937 gen(std::random_device{}()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

あなたに正確に一つstd::mt19937を与えることスレッドごとに実行し、関数の複数の呼び出しによってそれらを構築する時間を節約します。

+1

ありがとう、私は 'thread_local'キーワードを認識していませんでした。より一般的には、openmp並列領域を使ってこのスタイルを行うときに、 'thread_local'を使って物事を適切にスレッドローカルにする必要がありますか?並列領域内の変数が十分であると宣言したと思ったのですが? – Theolodus

+0

@Theolodus実際にはそうですね、並列領域にいることは既にスレッド固有になっています。私は、これは、スレッド固有であるということは、関数が頻繁に呼び出され、ジェネレータが一時的に複数回一時的に構成されるように初期化できれば、静的にできることを意味しますスレッド) – Galik

+0

'#pragma omp'はC++ 11スレッディングモデルに完全に従っていますか?スレッドローカルは 'std'スレッド内で動作することが保証されていますが、他のスレッドシステムでも動作するためには、スレッドシステムの作者からの保証が必要です。 – Yakk