2013-04-10 20 views
7

Używam nowych generatorów liczb losowych w C++ 11. Chociaż istnieją różne opinie, z tego thread wydaje się, że większość uważa, że ​​nie są bezpieczne dla wątków. W konsekwencji chciałbym stworzyć program, w którym każdy wątek używa własnego RNG.jak sprawić, aby każdy wątek używał własnego RNG w C++ 11

Przykład jest podany w odpowiednim omówieniu sposobu osiągnięcia tego z 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; 
} 

Kiedy uruchomić wielowątkowe i jednowątkowych wersję tego programu i śledzić w czasie, tyle samo czasu, aby zakończyć po wykonaniu. Ponadto, app nie ma tego samego rozmiaru w obu przypadkach, ale podejrzewam, że jest to tylko z powodu różnych nasion.

Pytanie: Czy podany przykład poprawnie pokazuje, jak zmusić każdy wątek do używania własnego RNG? Jeśli nie, czy mogę zobaczyć przykład tego, jak to się robi, lub uzyskać odniesienie do miejsca, w którym wyjaśniają, jak to osiągnąć?

Odpowiedz

6

Nie można udostępniać wystąpień losowego silnika między wieloma wątkami. Powinieneś zablokować pojedynczy silnik lub utworzyć jeden silnik dla każdego wątku (z innym materiałem siewnym (proszę zwrócić uwagę na odpowiedź e4e5f4 dotyczącą tworzenia równoległych silników MT)). W przypadku OpenMP można łatwo przechowywać jeden silnik na wątek w wektorze i pobrać go w wyniku omp_get_thread_num(), który leży między 0 a omp_get_num_threads()–1.

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

Dziękuję za ten przykład, który jest bardzo pomocny. Mam dwa pytania: (1) Czy mogę zapytać, dlaczego wybrałeś włączenie ': engines()'? Ściśle mówiąc, czy to jest wymagane? .... (2) Czy mogę używać obiektu 'rand' w późniejszej pętli w moim programie, który nie jest zrównoleglony? – BillyJean

+1

@BillyJean (1) Nie jest wymagane, ale mój osobisty styl wywoływania każdego elementu ctor na liście inicjalizatora, jeśli przynajmniej jeden jest wywoływany. (2) Nie w 100% pewny, ale myślę, że 'omp_get_thread_num()' zwraca 0 dla nierównoległego regionu, więc Tak. – hansmaad

+0

Ostatnie pytanie: Powiedz, że robię globalne 'RNG' i jego obiekt' rand' globalny. Zamiast warunkowego '(rand() <0.5)' teraz nazywam globalną funkcją 'func', która wykonuje pewne obliczenia zależne od' rand'. Czy użycie 'rand' w' func' nadal będzie bezpieczne dla wątków? Powiedziałbym "tak", ale chciałbym usłyszeć także twoją profesjonalną opinię. – BillyJean

2

Nie używałbym losowego siewu. Może to skończyć się nakładającymi się strumieniami. To ostatecznie wpłynie na ostateczną statystykę.

Proponuję niektóre sprawdzone rozwiązanie jak this

+2

Twoje "wypróbowane i przetestowane rozwiązanie w ten sposób" ostrzega: "Uwaga II: to nie jest jeszcze dobrze przetestowane, więc może zawierać wiele błędów". :-) – hansmaad

+0

Wolałbym zaufać MTDC niż losowemu sadzeniu :) – Nishanth

+0

Ja tylko się uśmiechnąłem, kiedy przeczytałem tę notatkę na stronie internetowej.Niemniej jednak dokument jest bardzo interesujący. Kiedy zaimplementowałem równoległe PRNG, po raz pierwszy zastanawiałem się, jak rozstawić silniki, ale nie mogłem znaleźć żadnych informacji. Rzeczywiście, nigdy nie mieliśmy (oczywistych) problemów w symulacjach Monte Carlo, używając prostego losowego siewu. – hansmaad

Powiązane problemy