Rand() und threads

hallo,

ich möchte in einer methode eines objekts, das von mehreren threads verwendet wird, zufallszahlen erzeugen. jetzt habe ich das problem, dass in jedem thread die selben zufallszahlen generiert werden. gibts irgendeine funktion (visual c++), die auch bei der verwendung mehrerer threads unterschiedliche zufallszahlen generiert oder hat irgendjemand sonst eine idee?

gruss tobias

Ich gehe mal davon aus, dass Deine besagtes Objekt ein sogenannte Singleton Object ist (sprich static).

Da kann es Probleme geben, wenn ein Thread auf den generierten Zufallswert zugreift,
waehrend ein andere Thread erst einen Wert generiert.
Das sollte erstmal ueber eine „Critical Section“ geschuetzt werden.

Fuer sogenannte SingletonThread Objekte gibt es in der Mai-Ausgabe C++ User Journal einen guten Artikel.
Entweder im Heft nachschlagen oder unter www.cuj.com mal nachschauen.

danke für den hinweis, werd ich mir mal ansehen.
gruss tobias

Wenn Du den Zufallszahlengenerator nicht speziell initialisierst, liefert der immer dieselben Zufallszahlen, unabhänig davon, wo oder in welchem Thread er verwendet wird.
Mit srand( … ) kannst Du einen Startpunkt setzen, sodass die nachfolgend mit rand() generierte Zufallszahlenfolge auch unterschiedlich wird. Dmait sollte sich Dein Problem darauf reduzieren, in jedem Thread den Zufallszahlengenerator individuell zu initialisieren. Meist wird das mit der Systemzeit gemacht (srand(( unsigned )time( NULL ))), Du solltest prüfen, ob das in Deinem Fall auch funktioniert.

Grüsse Safog

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

soweit ok, aber ich finde das deshalb unschön, da die threads eigentlich von zufallszahlen gar nichts wissen, sie greifen nur gemeinsam auf ein objekt zu, das intern zufallszahlen verwendet. deshalb dachte ich es gibt vielleicht eine andere methode zum erzeugen von zufallszahlen in c++, bei der es genügt, wenn ich den zufallszahlengenerator ein mal im konstruktor des besagten objekts initialisiere.

gruss tobias

Hallo tobias,

Die Frage ist:
Wird der Konstruktor EINMAL aufgerufen oder für JEDEN Thread EINMAL ?
Wenn letzteres der Fall ist und du jedesmal mit dem gleichen Wert initialisierts, dann laufen alle Zufallszahlengeneratoren schön synchron und du hast den von dir dahrgestellten Effekt.

Du musst also sicherstellen, dass der Zufallszahlengeneratoren nur EINMAL instanziert wird und alle Threats auf den GLEICHEN Zufallszahlengeneratoren zugreifen.

Ich vermute, dass du einfach eine Klasse gemacht hast, im Konstruktor wird der Zufallszahlengeneratoren initialisiert und es gibt eine Funktion, in dieser Klasse, welche eine Zufallszahl zurückgeben soll.

Jetzt gibt es zwei mögliche Fehler:

  1. Jeder Threat instantziert ein eigenes Object und somit hat jeder Thread einen EIGENEN Zufallszahlengenerator, welche alle mit dem gleichen Startwert arbeiten.

  2. Nach jedem Auslesen einer Zufallszahl wird der Destruktor aufgerufen und somit wird dein Zufallszahlengenerator jedesmal neu gestartet.

Aber ohne deine Sourcecode kann nicht mehr dazu sagen, sondern nur Raten.

MfG Peter(TOO)
P.S. SHIFT+INSERT ist eine schöne Tastenkombination.

soweit ok, aber ich finde das deshalb unschön, da die threads
eigentlich von zufallszahlen gar nichts wissen, sie greifen
nur gemeinsam auf ein objekt zu, das intern zufallszahlen
verwendet. deshalb dachte ich es gibt vielleicht eine andere
methode zum erzeugen von zufallszahlen in c++, bei der es
genügt, wenn ich den zufallszahlengenerator ein mal im
konstruktor des besagten objekts initialisiere.

der konstruktor wird nur EINMAL aufgerufen, alle threads greifen auf DASSELBE objekt zu, im konstruktor wird der zufallszahlengenerator initialisiert und trotzdem kriege ich in allen threads dieselben zufallszahlen.

gruss tobias

Hallo tobias,

der konstruktor wird nur EINMAL aufgerufen, alle threads
greifen auf DASSELBE objekt zu, im konstruktor wird der
zufallszahlengenerator initialisiert und trotzdem kriege ich
in allen threads dieselben zufallszahlen.

Scheinbar müssen wir zuerst etwas Therorie durchnehmen:

  1. Ein Programm besteht grundsätzlich aus einem Code- und einem Daten-Segment (das Ganze ist noch etwas differenzierter, aber das reicht für unsere Betrachtung), im ersteren sind die Befehle, im leteren alle Variablen abgelegt.

  2. Identische Threads verwenden ein gemeinsames Code-Segment, jeder Thread hat aber sein eigenes Data-Segment. Normalerweise arbeiten Bibliotheks-Funktionen mit dem Data-Segment des sie aufrufenden Threads.

  3. Ein Pseudo-Zufallszahlen-Generator, bestet aus etwas Code und einigen Variablen, welche zwischen den Aufrufen erhalten werden müssen, damit bein nächsten Aufruf eine neue Pseudo-Zufallszahl erzeugt werden kann.

  4. In deinem Fall wird für jeden Thread ein EIGENER Pseudo-Zufallszahlen-Generator erzeugt, d.h. er legt seine Variablen im Data-Segment des aufrufenden Threats ab.

Du musst jetzt halt dafür sorgen, dass entweder nur ein einziger Pseudo-Zufallszahlen-Generator, mit einem eigenen Data-Segment (entweder als eigener Thread oder die Daten müssen im globalen Data-Segment des Task abgelegt werden), erzeugt wird oder für jeden Thread muss der Pseudo-Zufallszahlen-Generator mit einem anderen Wert initialisiert werden.

MfG Peter(TOO)

hallo peter,

also erstens widersprechen sich meiner meinung nach deine zwei letzten postings etwas und zweitens danke für deine rührenden bemühungen mich über threads aufzuklären, aber ich bin durchaus im bilde hinsichtlich threads/prozessen usw. (aber auch sonst würde mir dein posting übrigens rein gar nix nützen). was ich eigentlich wissen wollte war, ob es irgendeinen ersatz für die rand() funktion gibt, bei der keine probleme mit threads auftreten.

gruss tobias

hallo tobias,

also erstens widersprechen sich meiner meinung nach deine zwei
letzten postings etwas und zweitens danke für deine rührenden
bemühungen mich über threads aufzuklären, aber ich bin
durchaus im bilde hinsichtlich threads/prozessen usw. (aber
auch sonst würde mir dein posting übrigens rein gar nix
nützen). was ich eigentlich wissen wollte war, ob es
irgendeinen ersatz für die rand() funktion gibt, bei der keine
probleme mit threads auftreten.

  1. Ich sehe keinen Wiederspruch, das Ganze wird nur von verschiedenen Standpunkten beschrieben.

  2. Wenn in deiner ViKa etwas stehen würde, wüsste ich auch ob ich es hier mit einem 14-Jährigen Schüler oder einem 40-Jährigen Programmierer mit 20-Jähriger Berufserfahrung zu tun habe und könnte mich anpassen, aber so kann ich nur raten.

  3. Im ersten Posting habe ich schon geschrieben, dass man ohne den SourceCode nur raten kann, was du falsch machst. rand() funktioniert auch in einer Multi-Thread-Umgebung, wenn man es richtig macht !

MfG Peter(TOO)

hallo peter,

also hier mal etwas code zum erklären, wie’s prinzipiell abläuft (macht zwar so keinen sinn, aber ich glaube kaum, dass du dir meinen gesamten code reinziehen willst, also hab ich’s hier mal vereinfacht dargestellt). die threads wissen aber in meinem ‚richtigen‘ code nix von zufallszahlen, deshalb fällt die möglichkeit weg, den generator in jedem thread zu initialisieren und deshalb glaube ich auch nicht, dass das problem mit rand() zu lösen ist und ich suche nach einer alternative.

gruss tobias

Gemeinsam genutzte Klasse:

class AClass
{

public:

 AClass() 
 {
 srand(time(NULL)); 
 }

 unsigned long random()
 {
 return rand();
 }
}

Thread Funktion:

unsigned \_\_stdcall threadFunction(void\* apointer)
{
 while(true)
 {
 cout random();
 }
}

hallo tobias,

also hier mal etwas code zum erklären, wie’s prinzipiell
abläuft (macht zwar so keinen sinn, aber ich glaube kaum, dass
du dir meinen gesamten code reinziehen willst, also hab ich’s
hier mal vereinfacht dargestellt).

Hier fehlen noch einige Angaben:
Welchen Compiler und OS benutzt du eigentlich ?

Wie Erzeugst du die Threats (füge das doch bitte noch deinem Code-Fragment hinzu) und wo kommt „void* apointer“ her (insbesondere finde ich es interresant, dass der Pointer vom typ VOID ist) ?

MfG Peter(TOO)

hallo peter,

windows 2000, visual c++ 6.0

threads werden mit _beginthreadex() erzeugt, zeiger auf void, weil die funktion _beginthreadex dies erfordert (unsigned __stdcall ThreadFunction(void* lpThreadParameter))

gruss tobias