2013-04-10 51 views
7

我在C++ 11中使用了新的隨機數生成器。雖然有不同的意見,但從這thread看來,大多數人認爲他們不是線程安全的。因此,我想製作一個程序,每個線程使用自己的RNG。如何讓每個線程在C++中使用自己的RNG 11

一個例子是在如何使用OpenMP做到這一點相關的討論給出:

#include <random> 
#include <iostream> 
#include <time.h> 
#include "omp.h" 

using namespace std; 



int main() 
{ 
    unsigned long long app = 0; 
    { 
     //mt19937_64 engine((omp_get_thread_num() + 1)); //USE FOR MULTITHREADING 
     mt19937_64 engine; //USE FOR SINGLE THREAD 
     uniform_real_distribution<double> zeroToOne(0.0, 1.0); 

     //#pragma omp parallel for reduction(+:app) //USE FOR MULTITHREADING 
     for (unsigned long long i = 0; i < 2000000000; i++) 
     { 
      if(zeroToOne(engine) < 0.5) app++; 
     } 
    } 
    cout << app << endl; 
    return 0; 
} 

當我運行此程序的多線程和單線程版本,並保持的時間軌跡,他們執行完後需要花費相同的時間。另外,app在兩種情況下的尺寸不一樣,但我懷疑這僅僅是因爲種子不同。

問題:提供的示例是否正確地顯示瞭如何強制每個線程使用自己的RNG?如果沒有,我能看到一個如何完成這個過程的例子,或者參考一些他們解釋如何實現這個目標的地方?

回答

6

您不能在多個線程之間共享隨機引擎的實例。您應該鎖定單個引擎或爲每個線程創建一個引擎(使用不同的種子(請注意e4e5f4有關創建並行MT引擎的答案))。對於OpenMP,您可以輕鬆地將每個線程的一個引擎存儲在一個向量中,並通過位於0和omp_get_num_threads()–1之間的omp_get_thread_num()的結果檢索它。

class RNG 
{ 
public: 
    typedef std::mt19937 Engine; 
    typedef std::uniform_real_distribution<double> Distribution; 

    RNG() : engines(), distribution(0.0, 1.0) 
    { 
     int threads = std::max(1, omp_get_max_threads()); 
     for(int seed = 0; seed < threads; ++seed) 
     { 
      engines.push_back(Engine(seed)); 
     } 
    } 

    double operator()() 
    { 
     int id = omp_get_thread_num(); 
     return distribution(engines[id]); 
    } 

    std::vector<Engine> engines; 
    Distribution distribution; 
}; 

int main() 
{ 
    RNG rand; 
    unsigned long app = 0; 

    #pragma omp parallel for reduction(+:app) 
    for (unsigned long long i = 0; i < 2000000000; i++) 
    { 
     if(rand() < 0.5) app++; 
    } 
} 
+0

一些久經考驗的解決方案感謝您對這個例子中,這是非常有幫助的。我有兩個問題:(1)我可以問你爲什麼選擇包含':engines()'?嚴格來說,這是必需的嗎? ....(2)我可以在我的程序中的後續循環中使用對象'rand',它不是並行化的嗎? – BillyJean 2013-04-10 11:49:24

+1

@BillyJean(1)不需要但我的個人風格調用初始化列表中的每個元素ctor,如果至少有一個被調用。 (2)不是100%確定的,但我認爲對於非並行區域,omp_get_thread_num()返回0,所以是。 – hansmaad 2013-04-10 12:02:41

+0

最後一個問題:假設我讓全局的'RNG'和它的對象'rand'全局。現在我調用一個全局函數'func',而不是條件'(rand()<0.5)',它執行一些依賴於'rand'的計算。在'func'中使用'rand'仍然是線程安全的嗎?我會說'是的',但我想聽聽你的專業意見。 – BillyJean 2013-04-10 13:12:03

2

我會避免使用隨機播種。它可能以重疊的流結束。這最終會影響最終的統計數據。

我建議像this

+2

您的「經過測試的解決方案如此」給出了警告:「警告II:這還沒有很好地測試,所以它可能包含很多錯誤。」 :-) – hansmaad 2013-04-10 11:19:21

+0

我寧願信任MTDC,也不願意隨機播種:) – Nishanth 2013-04-10 12:10:51

+0

當我在網站上閱讀這篇文章時,我只是笑了笑。儘管如此,文件非常有趣。當我第一次實施並行化PRNG時,我想知道如何播種引擎,但是我找不到任何信息。事實上,我們從未在使用簡單的隨機播種的蒙特卡羅模擬中出現(明顯的)問題。 – hansmaad 2013-04-10 12:26:05