Initialisierung nur beim ersten Aufruf der Funktion - Multithreading
-
Hallo,
eine Initialisierung soll nur beim ersten Aufruf einer Funktion stattfinden.
Dazu wollte ich ein statisches Objekt einer Klasse anlegen, die die Initialisierung im Konstruktor vornimmt. Sieht dann ungefähr so aus:class SeedInitializer { public: SeedInitializer() { srand(static_cast<unsigned>(time(NULL))); } }; int getRandomNumber() { static SeedInitializer seedInitializer; return 42; }
Ist das prinzipiell richtig so oder macht man sowas eher nicht?
So, auf jeden Fall funktioniert es so in einer Single-Threaded-Anwendung.
Aber wenn ich jetzt mehrere Threads habe (ich weiß, Standard C++ hat kennt Threads ;)) die die Funktion gleichzeitig aufrufen, kann es dann passieren das trotz des static Schlüsselworts mehrere Instanzen von SeedInitializer erzeugt werden?
-
Mach doch einfach eine globale Variable "int rand_initialized = 0", nur wenn die 0 ist initialisierst du den Zufallsgenerator und setzt sie auf 1.
--> wird nur einmal gemacht.
-
Dann muss ich die globale Variable auch Schützen vor gemeinsamen Zugriffen, entweder per Critical Section oder durch Benutzung von atomaren Integer-Operationen.
Dann könnte ich genauso gut sowas machen:
cs.enter();
static SeedInitializer seedInitializer;
cs.leave();
-
fg schrieb:
Aber wenn ich jetzt mehrere Threads habe (ich weiß, Standard C++ hat kennt Threads ;)) die die Funktion gleichzeitig aufrufen, kann es dann passieren das trotz des static Schlüsselworts mehrere Instanzen von SeedInitializer erzeugt werden?
Ja, das kann passieren.
Der Standard hat zwar ursprünglich noch leidlich versucht das Verhalten für den Fall genauer zu erklären (funktioniert hat es aber trotzdem nicht), aber spätestens mit TC1 (dem ersten "Nachtrag") gilt das Verhalten für diesen Fall offiziell als undefiniert. Man kommt also um Synchronisationsmassnahmen nicht herum, wenn man keine Probleme haben will.
Allerdings verstehe ich nicht, warum immer wieder (auch in anderen Threads) versucht wird srand "on demand" aufzurufen, ein Aufruf von srand() in main(), vor dem ersten Starten von Threads sollte doch für die meisten Anwendungen das Problem lösen. Es ist natürlich trotzdem sinnvoll von den Problemen bei der "on demand"-Lösung im Threading zu wissen, aber für Zufallszahlen mit rand/srand lohnt der Aufwand einfach nicht.