Verwenden von rand() von stdlib aus mehreren Threads

Lesezeit: 5 Minuten

Verwenden von rand von stdlib aus mehreren Threads
SIMEL

Ich habe mehrere Threads, die alle die gleiche Funktion ausführen. In jedem davon erzeugen sie mehrmals eine andere Zufallszahl. Wir haben versucht, dies durch Putten zu tun srand(time(0)) am Anfang der Funktion, aber es scheint, dass sie alle die gleiche Nummer bekommen.

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

  • Wahrscheinlich sind Sie mit den neuen Zufallszahlengeneratoren in C++0x besser dran. Welchen Compiler verwendest du?

    – fredoverflow

    28. Mai 2011 um 11:37 Uhr

  • Welches Betriebssystem verwendest du Windows/Linux?

    – ob_dev

    28. Mai 2011 um 11:45 Uhr

  • Wenn alle Laufflächen denselben srand() verwenden, erhalten Sie dieselben Zufallszahlen

    – ob_dev

    28. Mai 2011 um 11:46 Uhr


  • Rufen Sie rand() nicht von mehreren Threads aus auf. Verwenden Sie die Zufallszahlengeneratoren in C++0x. Diese sind auch in Boost verfügbar.

    – Johan Rade

    28. Mai 2011 um 13:18 Uhr

  • Ich habe beobachtet, dass rand() jedes Mal, wenn ein Thread startet, über die gleiche Sequenz beginnt. In meiner Anwendung starte ich einen Thread in einer Schleife, und rand() wiederholt die gleiche Sequenz in jeder Iteration. rand() ist bei Multithreading definitiv tabu. Ich habe dies behoben, indem ich diese neueren C++-Generatoren wie oben vorgeschlagen verwendet habe.

    – Paulo Carvalho

    14. Juli 2019 um 11:25 Uhr

1646637010 312 Verwenden von rand von stdlib aus mehreren Threads
Frédéric Hamidi

sand() startet den Zufallszahlengenerator. Sie sollten nur anrufen müssen srand(time(NULL)) einmal während des Starts.

In der Dokumentation heißt es jedoch:

Die Funktion rand() ist nicht ablaufinvariant oder Thread-sicher, da es einen verborgenen Zustand verwendet, der bei jedem Aufruf geändert wird. Dies kann nur der Seed-Wert sein, der vom nächsten Aufruf verwendet werden soll, oder es könnte etwas Ausgefeilteres sein. Um ein reproduzierbares Verhalten in einer Thread-Anwendung zu erhalten, muss dieser Zustand explizit gemacht werden. Die Funktion
rand_r() wird mit einem Zeiger auf an versorgt unsigned int, als Zustand zu verwenden. Dies ist eine sehr kleine Zustandsmenge, daher ist diese Funktion ein schwacher Pseudozufallsgenerator. Versuchen
drand48_r(3) stattdessen.

Der hervorgehobene Teil des Obigen ist wahrscheinlich der Grund, warum alle Ihre Threads dieselbe Nummer erhalten.

  • Es ist nicht klar, wie dieses sehr eng umsetzungsspezifische Zitat auf die ursprüngliche Frage zutrifft. Letzteres gibt nicht an, welche Implementierung verwendet wird. rand() kann leicht threadsicher sein. Es kommt auf eine konkrete Umsetzung an.

    – Ant

    7. September 2018 um 9:09 Uhr


  • @AnT: Aber rand() ist nicht erforderlich Thread-sicher zu sein, sodass ein portables Multithread-Programm es nicht sicher verwenden kann (außer durch Schützen mit einem Mutex oder ähnlichem). C17 7.22.2.1p3: „Die rand -Funktion ist nicht erforderlich, um Datenrennen mit anderen Aufrufen von Funktionen zur Generierung von Pseudozufallsfolgen zu vermeiden [such as itself]”.

    – Nate Eldredge

    16. Oktober 2021 um 7:00 Uhr

Da Sie C++ anstelle von C verwenden, können Sie möglicherweise die Threading-Probleme vermeiden, die häufig 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 separate Engine und Distribution verwenden. Das Beispiel wirkt 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 und Booste zufällig bei der Beantwortung dieser Frage.

Von dem rand Manpage:

Die Funktion rand() ist nicht wiedereintritts- oder threadsicher, da sie einen verborgenen Zustand verwendet, der bei jedem Aufruf geändert wird.

Verwenden Sie es also nicht mit Thread-Code. Verwenden rand_r (oder drand48_r wenn Sie auf Linux/glibc sind). Setzen Sie jedem RNG einen anderen Wert (Sie könnten einen ersten RNG im Haupt-Thread setzen, um zufällige Seeds für die in jedem Thread zu erzeugen).

  • Interessant, rand scheint eine Thread-sichere Version von zu sein rand_r in glibc, nicht umgekehrt (wenn ich interpretiere der Quellcode korrekt).

    – Groo

    19. August 2020 um 12:52 Uhr


  • Du bist nicht. Sie sehen sich genau den internen Zustand an, der es nicht Thread-sicher macht.

    – borrden

    10. Oktober 2020 um 2:20 Uhr


Wenn Sie die Threads alle gleichzeitig starten, ist die an srand gesendete Zeit wahrscheinlich für jeden Thread gleich. Da sie alle denselben Seed haben, geben sie alle dieselbe Sequenz zurück. Versuchen Sie, etwas anderes wie eine Speicheradresse aus einer lokalen Variablen zu verwenden.

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

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

Die Visual C++-Laufzeitumgebung verwendet den internen Status pro Thread, daher ist es sicher, srand() für jeden Thread aufzurufen. Aber wie Neil betonte, werden Sie wahrscheinlich alle Threads mit demselben Wert säen – also stattdessen mit (Zeit + Thread-ID) säen.

Verwenden Sie für die Portabilität natürlich Random-Objekte anstelle der Rand-Funktion, und dann wären Sie überhaupt nicht auf den versteckten Zustand angewiesen. Sie benötigen immer noch ein Objekt pro Thread, und es ist immer noch eine gute Idee, jedes Objekt mit (Zeit + Thread-ID) zu versehen.

  • Ich werde “Windows” kommentieren, damit die Leute leichter auf diese Antwort landen, wenn sie MS Visual C++ in einem Windows-Kontext verwenden.

    – omatai

    11. März 2021 um 0:54 Uhr

1646637011 322 Verwenden von rand von stdlib aus mehreren Threads
Coder

Das ist eine gute Frage. Ich kann es nicht direkt beantworten, weil ich denke, dass es größere Probleme gibt. Es scheint nicht einmal klar zu sein, dass rand überhaupt Thread-sicher ist. Es behält den internen Zustand bei und es scheint nicht genau definiert zu sein, ob dies pro Prozess oder pro Thread ist und ob es pro Prozess ist, wenn es Thread-sicher ist.

Um sicherzugehen, würde ich einen Mutex um jeden Zugriff sperren.

Oder verwenden Sie vorzugsweise ein besser definiertes Generate wie z. B. from Schub

  • Ich werde “Windows” kommentieren, damit die Leute leichter auf diese Antwort landen, wenn sie MS Visual C++ in einem Windows-Kontext verwenden.

    – omatai

    11. März 2021 um 0:54 Uhr

963860cookie-checkVerwenden von rand() von stdlib aus mehreren Threads

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy