2016-11-17 4 views
-2
#include <random> 

int f() { 

    std::random_device seeder; 
    std::mt19937 engine(seeder()); 
    std::uniform_int_distribution<int> dist(1, 6); 

    return dist(engine); 

} 

Können mehrere Threads diese Funktion sicher aufrufen? Ist die Funktion Thread sicher? Es ist reduant, std::random_device seeder; und std::mt19937 engine(seeder()); jedes Mal anzurufen?Ist Mersenne Twister Thread sicher für cpp

+2

Warum das "C" -Tag? Das hat nichts mit C. zu tun. – UnholySheep

+0

Ich verstehe nicht wirklich, warum ich downvotes bekomme. Ich frage, ob das Gewinde sicher ist und ob es nicht nötig ist, den Samen zu erneuern. – cateof

+0

Wahrscheinlich wegen ähnlicher Fragen mit langen und detaillierten Antworten? –

Antwort

1

Nein C++ std Typ verwendet globale Daten in einer nicht Thread-sicheren Weise. Auf zwei nicht verwandte Instanzen eines solchen Typs kann in verschiedenen Threads zugegriffen werden.

Standardmäßig kann auf eine Instanz eines Typs von zwei Threads ohne Synchronisierung nicht zugegriffen werden.

Sie sind lokale Variablen erstellt. Diese lokalen Variablen sind mit keiner anderen Instanz ihres Typs verwandt. Hier gibt es keine Threadsicherheitsprobleme.

Pseudozufallswerte werden am effizientesten durch den Status und die Wiederverwendung erzeugt. Sie tun dies nicht, also ist Ihre Zufallszahl von 1 bis 6 relativ teuer zu erstellen.

std::random_device seeder; 
std::mt19937 engine(seeder()); 
std::uniform_int_distribution<int> dist(1, 6); 
return dist(engine); 

Ihre Verwendung von std::mt19937 ist redundant. Sie erstellen bereits eine random_device, die direkt an dist weitergeleitet werden kann, und erstellt dann eine engine daraus und dann die engine. Die Verwendung von engine hier ist nutzlos.

Traditionsgemäß Sie schaffen eine engine (einer Art, wie mt19937) einmal von einem seeder.Sie speichern dann die engine und übergeben sie wiederholt an Distributionen.

Dies macht die relativ teure "echte Zufallsgenerierung" einmal, um über die Engine durch Verteilung eine lange Reihe von Pseudozufallszahlen zu generieren.

Beachten Sie jedoch, dass eine solche Verwendung einen Preis hat; Sie müssen die engine speichern und Sie müssen Mehrfach-Thread-Zugriff darauf verhindern.

Der "richtige" Weg, dies zu tun, ist, ein Objekt zu haben, das zufällige Werte für Sie erzeugt und es dort herumgibt, wo Sie es brauchen. Das Speichern des ursprünglichen Startwerts würde es Ihnen auch ermöglichen, die Ausführung der betreffenden Zufallszahl zu wiederholen.

Wenn Sie die Idee nicht mögen, Ihren zufälligen Zustand explizit zu umgehen, könnten Sie eine (oder static mit einer mutex Wache) verwenden.

thread_local std::mt19937 engine(std::random_device{}()); 
std::uniform_int_distribution<int> dist(1, 6); 
return dist(engine); 

Dies schafft eine engine pro Faden, und die engine mit einem Wert von Ihrem random_device initialisiert wird.

2

Können mehrere Threads diese Funktion sicher aufrufen? Ist die Funktion Thread sicher?

Diese spezielle Funktion ist threadsicher. Es ist in Ordnung, Zufallszahlengeneratoren, Engines und Verteilungen zu erstellen und eine Zahl in einer lokalen Funktion in mehreren Threads zu generieren.

Natürlich kann die Ausgabe von mehreren Threads verschachtelt werden, da nicht synchronisiert ist.

Muß ich den Motor in jedem Funktionsaufruf

Während das tut Garantie Thread-Sicherheit initialisieren, das ist das Gegenteil von dem, was Sie tun müssen. Durch die Initialisierung der Engine wird die Reihenfolge der Zufälligkeit direkt von der Sämaschine abhängig. Und es fügt natürlich Overhead hinzu, um die Engine zu initialisieren.

oder wäre es besser, die ersten beiden Zeilen (Seeder und Engine) in einem Klassenkonstruktor zu platzieren?

Sie können eine Wrapper-Klasse verwenden, müssen dies aber nicht tun. Dies ist orthogonal zur Frage, ob Sie bei jedem Funktionsaufruf eine neue Engine-Instanz erstellen. Solange jeder Funktionsaufruf dieselbe Engine wie vorherige Aufrufe verwendet, gibt es in dieser Hinsicht kein Problem mit der Zufälligkeit.

Aber die Verwendung desselben Motors über Gewinde ist in der Tat nicht threadsicher. Sie können stattdessen in jedem Thread eine Engine verwenden oder eine gemeinsam genutzte Engine mit einem Mutex schützen, was jedoch einen erheblichen Aufwand bedeutet.

+0

Ich habe die Frage aktualisieren. – cateof