2013-04-10 10 views
7

verwenden lässt, verwende ich die neuen Zufallszahlengeneratoren in C++ 11. Obwohl es unterschiedliche Meinungen gibt, scheint es, dass die Mehrheit der Meinung ist, dass sie nicht threadsicher sind. Als Konsequenz möchte ich ein Programm erstellen, bei dem jeder Thread seinen eigenen RNG verwendet.Wie man jeden Thread seinen eigenen RNG in C++ 11

Ein Beispiel ist in der damit verbundenen Diskussion gegeben, wie dies mit OpenMP zu erreichen:

#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; 
} 

Wenn ich die Multi-Threaded-und Single-Threaded-Version dieses Programm ausführen und verfolgen die Zeit, sie nehmen Sie die gleiche Zeit, um nach der Ausführung zu beenden. Auch app hat nicht die gleiche Größe in den beiden Fällen, aber ich vermute, dass nur wegen der verschiedenen Samen ist.

Frage: Zeigt das angegebene Beispiel korrekt, wie jeder Thread seinen eigenen RNG verwendet? Wenn nicht, kann ich ein Beispiel dafür sehen oder einen Verweis auf einen Ort bekommen, an dem sie erklären, wie dies zu erreichen ist?

Antwort

6

Sie dürfen keine Instanzen einer zufälligen Engine zwischen mehreren Threads teilen. Sie sollten entweder eine einzelne Engine sperren oder eine Engine für jeden Thread erstellen (mit unterschiedlichem Seed (beachten Sie die Antwort von e4e5f4 bezüglich der Erstellung von parallelen MT-Engines)). Im Fall von OpenMP können Sie einfach eine Engine pro Thread in einem Vektor speichern und sie durch das Ergebnis omp_get_thread_num() abrufen, das zwischen 0 und omp_get_num_threads()–1 liegt.

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

Sie vorschlagen, für dieses Beispiel danken, die sehr hilfreich ist. Ich habe zwei Fragen: (1) Darf ich fragen, warum Sie sich für ': engines()' entschieden haben? Streng genommen, ist das erforderlich? .... (2) Darf ich das Objekt 'rand' in einer späteren Schleife in meinem Programm verwenden, das nicht parallelisiert ist? – BillyJean

+1

@BillyJean (1) Nicht erforderlich, aber mein persönlicher Stil, um jedes Element ctor in der Initialisierungsliste aufzurufen, wenn mindestens einer aufgerufen wird. (2) Nicht 100% sicher, aber ich denke 'omp_get_thread_num()' gibt 0 für nicht parallelisierte Region zurück, also Ja. – hansmaad

+0

Eine letzte Frage: Sagen wir, ich mache 'RNG' global und ihr Objekt' rand' global. Statt der Bedingung '(rand() <0.5) 'rufe ich jetzt eine globale Funktion' func' auf, die einige Berechnungen durchführt, die von 'rand' abhängen. Wird die Verwendung von 'rand' in' func' immer noch threadsicher sein? Ich würde "ja" sagen, aber ich würde gerne Ihre Meinung hören. – BillyJean

2

Ich würde von zufälligen Seeding verzichten. Es könnte zu überlappenden Streams kommen. Dies wird sich letztendlich auf die endgültige Statistik auswirken.

würde ich einige bewährte Lösung wie this

+2

Ihre "bewährte Lösung wie folgt" warnt: "Vorsicht II: Dies ist noch nicht gut getestet, so dass es viele Fehler enthalten kann." :-) – hansmaad

+0

Ich würde eher MTDC als zufällige Seeding vertrauen :) – Nishanth

+0

Ich lächelte nur, wenn ich diese Notiz auf der Website lesen.Trotzdem ist das Dokument sehr interessant. Als ich zum ersten Mal parallelisierte PRNG implementierte, fragte ich mich, wie ich die Engines erstellen sollte, aber ich konnte keine Informationen finden. Tatsächlich hatten wir nie Probleme in Monte-Carlo-Simulationen, die ein einfaches zufälliges Seeding verwendeten. – hansmaad

Verwandte Themen