Bekanntermaßen schreibt man wie folgt mithilfe des Operators
std::cout
Intern wird alles, was man schreibt, in einem Stream-Puffer gespeichert und an die gewünschte Stelle geschrieben, wenn der Programmierer die Member-Funktion flush() aufruft oder der Puffer-Speicher voll ist und daher automatisch geleert wird.
Die Anweisung zur Leerung an einen Stream ist ganz einfach: Es genügt, std::endl in den Stream zu schreiben. Dies entspricht dem Schreiben von n in den Stream und dem anschließenden Leeren des Streams.
Zur Vereinfachung wird das Prinzip angewandt, dass beim Leeren eines Streams die aktuelle Mitteilung endet und eine neue Mitteilung beginnt, wie im Code unten zu sehen:
Um das Schreiben von Mitteilungen thread-sicher zu machen, sind die folgenden fünf Schritte auszuführen:
Der unten aufgeführte Code zeigt diese Schritte:
Das Monitoring der Leerung ist nicht so einfach, wie es scheint. Dazu muss die Funktion sync() des Puffer-Speichers des Streams aufgehoben werden. Listing C zeigt die Klasse basic_message_handler_log, in der alle diese Details verborgen sind. Man kann jedoch auch einfach eine eigene Protokoll-Klasse erstellen und die Funktion on_new_message überschreiben, die nach dem Schreiben einer neuen Mitteilung aufgerufen wird.
Der Trick mit den temporären Variablen
Nochmals zusammengefasst: Jeder Thread sollte seinen eigenen Stream S besitzen, wobei S eine Referenz auf U enthält (der einen thread-sicheren Zugang benötigt). Die einfachste Methode, jeden Thread mit einem eigenen Stream S zu versehen, liegt in der kontinuierlichen Verwendung temporärer Variablen. Diese sind grundsätzlich thread-sicher, da nur der jeweils zur Verwendung der Variablen eingesetzte Thread auf sie zugreift. Der Trick besteht in der Verwendung einer Funktion get_log, die intern eine statische Variable besitzt (den zugehörigen Stream U) und eine temporäre Variable (den Stream S) ausgibt, wie in Listing D dargestellt.
Die in Listing D gezeigte Methode ist nicht nur einfacher als die meisten alternativen Verfahren, sie ist auch am effizientesten. Ein Locking findet nur beim Leeren des Streams statt.
Lösung 1
Die Klasse thread_safe_log ist von basic_message_handler_log abgeleitet (wie in Listing C gezeigt) und überschreibt on_new_message, wobei in thread-sicherer Weise in das zugehörige Protokoll geschrieben wird. Dabei stellt sich die Frage, wo das kritische Section-Objekt untergebracht werden soll. Um thread_safe_log zu entkoppeln, muss eine weitere Klasse erstellt werden – internal_thread_safe_log –, die das Threading übernimmt.
Eine Funktion get_log sieht wie folgt aus:
Wichtig sind hierbei die Klassen internal_thread_safe_log und thread_safe_log, auf sie wird in diesem Artikel häufig Bezug genommen.
Listing E zeigt die oben genannten Methoden. Dabei ist zu beachten, dass der Code in Listing F zur korrekten Ausführung die in Listing F enthaltene Datei CriticalSection.h benötigt.
Es lässt sich nun Folgendes feststellen:
Wenn man diese Punkte nicht beachtet, kann dies schwerwiegende Folgen haben. Beispielsweise könnte U auf das deutsche Locale gesetzt sein (so dass 5.235 als 5,235 geschrieben wird). Würde S nun beim Drucken von Zahlen das standardmäßige Locale verwenden, würde die Ausgabe völlig falsch ausgelegt werden.
Listing E enthält außerdem einen Test. (Zu seiner Ausführung sind die Listings C und F erforderlich.) Der Test verwendet out.txt als zugehörigen Stream U. Er erstellt 200 konkurrierende Threads, wobei jeder der Threads 500 Mitteilungen folgender Art schreibt:
Wenn der Thread mit Index 10 die elfte Mitteilung schreibt, wird das Locale von U in Deutsch geändert. Alle nachfolgenden Mitteilungen schreiben dann „writing double 5,23“ statt „writing double 5.23“.
Das jüngste Update bringt insgesamt zwölf Fixes. Schadcode lässt sich unter Umständen ohne Interaktion mit…
Eine softwarebasierte Workstation soll es Ingenieuren erlauben, sämtliche Steuerungen zentral zu verwalten. Pilotkunde ist Ford.
Kryptodiebstahl und finanzieller Gewinn sind laut ESET-Forschungsbericht die vorrangigen neuen Ziele.
Schwachstellen aus der ThroughTek Kaylay-IoT-Plattform. Dringend Update-Status der IoT-Geräte prüfen.
Fast acht Milliarden Euro fließen in die deutsche Region der AWS European Sovereign Cloud. Das…
Internet in den eigenen vier Wänden ist heutzutage nicht mehr wegzudenken. Denn egal, ob Homeoffice…