50 Stimmen

Verwendung von stdlibs rand() von mehreren Threads aus

Ich habe mehrere Threads, die alle die gleiche Funktion ausführen. In jedem dieser Threads wird mehrmals eine andere Zufallszahl erzeugt. Wir haben versucht, dies zu tun, indem wir srand(time(0)) am Anfang der Funktion, aber es scheint, dass sie alle die gleiche Zahl erhalten.

Müssen wir anrufen srand(time(0)) nur einmal pro Programm, d.h. zu Beginn von main (zum Beispiel), am Anfang jeder Funktion, die mehrmals aufgerufen wird, oder etwas anderes?

47voto

Frédéric Hamidi Punkte 249635

srand() sät den Zufallszahlengenerator. Sie sollten nur folgende Aufrufe machen müssen srand(time(NULL)) einmal während des Starts.

Allerdings heißt es in der Dokumentation:

Die Funktion rand() es nicht ablaufinvariant oder thread-sicher da es versteckte Status verwendet, der bei jedem Aufruf geändert wird. Dies könnte nur der Startwert sein, der beim nächsten Aufruf verwendet wird, oder es kann kann etwas Komplizierteres sein. Um ein ein reproduzierbares Verhalten in einer Anwendung zu erhalten, muss dieser Zustand explizit gemacht werden. Die Funktion rand_r() wird mit einem Zeiger auf eine unsigned int als Zustand verwendet werden. Dies ist eine sehr kleine Menge an Status, daher ist diese Funktion eine schwache Pseudo-Zufallsgenerator sein. Versuchen Sie drand48_r (3) statt.

Der hervorgehobene Teil des obigen Satzes ist wahrscheinlich der Grund dafür, dass alle Ihre Themen die gleiche Nummer erhalten.

11voto

kshepherd Punkte 618

Da Sie C++ und nicht C verwenden, können Sie möglicherweise die Threading-Probleme vermeiden, die oft mit srand/rand verbunden sind, indem Sie c++11 verwenden. Dies hängt von der Verwendung eines aktuellen Compilers ab, der diese Funktionen unterstützt. Sie würden für jeden Thread eine eigene Engine und Distribution verwenden. Das Beispiel funktioniert wie ein Würfel.

#include <random>
#include <functional>

std::uniform_int_distribution<int> dice_distribution(1, 6);
std::mt19937 random_number_engine; // pseudorandom number generator
auto dice_roller = std::bind(dice_distribution, random_number_engine);
int random_roll = dice_roller();  // Generate one of the integers 1,2,3,4,5,6.

Ich bezog mich auf Wikipedia C++11 y Zufällige Steigerung bei der Beantwortung dieser Frage.

8voto

Mat Punkte 195740

Von der rand man-Seite:

Die Funktion rand() ist nicht ablaufinvariant oder thread-sicher, da sie einen versteckten Zustand verwendet, der bei jedem Aufruf geändert wird.

Verwenden Sie ihn also nicht mit Threaded Code. Verwenden Sie rand_r (ou drand48_r wenn Sie unter Linux/Glibc arbeiten). Setzen Sie jeden RNG mit einem anderen Wert (Sie könnten einen ersten RNG im Haupt-Thread setzen, um zufällige Werte für die RNGs in den einzelnen Threads zu erzeugen).

7voto

Peter Heath Punkte 105

Wenn Sie die Threads alle zur gleichen Zeit starten, ist die an srand gesendete Zeit wahrscheinlich für jeden Thread gleich. Da sie alle den gleichen Seed haben, geben sie alle die gleiche Sequenz zurück. Versuchen Sie, etwas anderes zu verwenden, z. B. eine Speicheradresse aus einer lokalen Variable.

4voto

Michael Entin Punkte 6047

C wurde nicht für Multithreading entwickelt, daher ist das Verhalten von srand() bei Multithreading nicht definiert und hängt von der C-Laufzeitbibliothek ab.

Viele Unix/Linux C-Laufzeitbibliotheken verwenden einen einzigen statischen Zustand, auf den von mehreren Threads aus nicht sicher zugegriffen werden kann. Daher können Sie mit diesen C-Laufzeitbibliotheken srand() und rand() von mehreren Threads aus überhaupt nicht verwenden. Andere Unix-C-Laufzeitbibliotheken verhalten sich möglicherweise anders.

Die Visual C++-Laufzeit verwendet einen internen Zustand pro Thread, so dass es sicher ist, srand() für jeden Thread aufzurufen. Aber wie Neil schon sagte, werden Sie wahrscheinlich alle Threads mit demselben Wert seeden - also seeden Sie stattdessen mit (time + thread-id).

Aus Gründen der Übertragbarkeit sollten Sie natürlich Random-Objekte statt der Rand-Funktion verwenden, dann sind Sie nicht von einem verborgenen Zustand abhängig. Sie brauchen immer noch ein Objekt pro Thread, und jedes Objekt mit (time + thread-id) zu bestücken ist immer noch eine gute Idee.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X