Im Allgemeinen gehe ich davon aus, dass Streams nicht synchronisiert sind. Es ist Sache des Benutzers, eine entsprechende Sperrung vorzunehmen. Erhalten Dinge wie cout
eine Sonderbehandlung in der Standardbibliothek?
Das heißt, wenn mehrere Threads schreiben, cout
können sie das cout
Objekt beschädigen? Ich verstehe, dass selbst wenn synchronisiert, Sie immer noch zufällig verschachtelte Ausgabe erhalten würden, aber ist diese Verschachtelung garantiert. Ist es sicher, cout
von mehreren Threads aus zu verwenden?
Ist dieser Anbieter abhängig? Was macht gcc?
Wichtig : Bitte geben Sie eine Referenz für Ihre Antwort an, wenn Sie "Ja" sagen, da ich einen Beweis dafür benötige.
Mein Anliegen ist auch nicht die zugrunde liegenden Systemaufrufe, diese sind in Ordnung, aber die Streams fügen eine Pufferschicht hinzu.
printf
leuchtet hier die gesamte Ausgabe aufstdout
einmal. bei Verwendung würdestd::cout
jedes Glied der Ausdruckskette separat ausgegeben werden anstdout
; dazwischen kann es einen anderen Thread geben, auf den geschrieben wirdstdout
, wodurch die Reihenfolge der endgültigen Ausgabe durcheinander gebracht wird.Antworten:
Der C ++ 03-Standard sagt nichts darüber aus. Wenn Sie keine Garantie für die Thread-Sicherheit von etwas haben, sollten Sie es als nicht thread-sicher behandeln.
Von besonderem Interesse ist hier die Tatsache, dass
cout
gepuffert ist. Selbst wenn sich die Aufrufe vonwrite
(oder was auch immer diesen Effekt in dieser bestimmten Implementierung bewirkt) gegenseitig ausschließen, kann der Puffer von den verschiedenen Threads gemeinsam genutzt werden. Dies führt schnell zu einer Beschädigung des internen Status des Streams.Und selbst wenn der Zugriff auf den Puffer garantiert threadsicher ist, was wird Ihrer Meinung nach in diesem Code passieren?
Sie möchten wahrscheinlich, dass jede Zeile hier in gegenseitigem Ausschluss handelt. Aber wie kann eine Implementierung das garantieren?
In C ++ 11 haben wir einige Garantien. Das FDIS sagt in §27.4.1 [iostream.objects.overview] Folgendes:
Sie erhalten also keine beschädigten Streams, müssen diese jedoch manuell synchronisieren, wenn die Ausgabe kein Müll sein soll.
quelle
cout.sync_with_stdio()
zutrifft, ist die Verwendungcout
der Ausgabe von Zeichen aus mehreren Threads ohne zusätzliche Synchronisierung genau definiert, jedoch nur auf der Ebene einzelner Bytes. Socout << "ab";
undcout << "cd"
in verschiedenen Threads ausgeführt, kann beispielsweise ausgegeben werdenacdb
, kann aber kein undefiniertes Verhalten verursachen.Das ist eine gute Frage.
Erstens hat C ++ 98 / C ++ 03 kein Konzept von "Thread". In dieser Welt ist die Frage also bedeutungslos.
Was ist mit C ++ 0x? Siehe Martinhos Antwort (die mich zugegebenermaßen überrascht hat).
Wie wäre es mit bestimmten Implementierungen vor C ++ 0x? Nun, hier ist zum Beispiel der Quellcode für
basic_streambuf<...>:sputc
aus GCC 4.5.2 ("streambuf" -Header):Dies führt eindeutig zu keiner Verriegelung. Und das tut es auch nicht
xsputn
. Und dies ist definitiv die Art von Streambuf, die Cout verwendet.Soweit ich das beurteilen kann, führt libstdc ++ keine Sperren für die Stream-Operationen durch. Und ich würde keine erwarten, da das langsam sein würde.
Bei dieser Implementierung ist es offensichtlich möglich, dass sich die Ausgabe von zwei Threads gegenseitig beschädigt ( nicht nur verschachtelt).
Könnte dieser Code die Datenstruktur selbst beschädigen? Die Antwort hängt von den möglichen Wechselwirkungen dieser Funktionen ab. Beispiel: Was passiert, wenn ein Thread versucht, den Puffer zu leeren, während ein anderer versucht, aufzurufen,
xsputn
oder was auch immer. Dies hängt möglicherweise davon ab, wie Ihr Compiler und Ihre CPU die Speicherladevorgänge und -speicher neu anordnen. Es würde eine sorgfältige Analyse erfordern, um sicher zu sein. Es hängt auch davon ab, was Ihre CPU tut, wenn zwei Threads versuchen, denselben Speicherort gleichzeitig zu ändern.Mit anderen Worten, selbst wenn es in Ihrer aktuellen Umgebung einwandfrei funktioniert, kann es beim Aktualisieren Ihrer Laufzeit, Ihres Compilers oder Ihrer CPU zu Problemen kommen.
Zusammenfassung: "Ich würde nicht". Erstellen Sie eine Protokollierungsklasse, die ordnungsgemäß sperrt, oder wechseln Sie zu C ++ 0x.
Als schwache Alternative könnten Sie cout auf ungepuffert setzen. Es ist wahrscheinlich (obwohl nicht garantiert), dass die gesamte Logik in Bezug auf den Puffer übersprungen und
write
direkt aufgerufen wird. Obwohl das unerschwinglich langsam sein könnte.quelle
cout
.www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
und außerdem: Sind Standardausgabestreams in C ++ threadsicher (cout, cerr, clog)?
AKTUALISIEREN
Schauen Sie sich die Antwort von @Martinho Fernandes an, um zu erfahren, was der neue Standard C ++ 11 dazu sagt.
quelle
Wie andere Antworten erwähnen, ist dies definitiv herstellerspezifisch, da der C ++ - Standard das Threading nicht erwähnt (dies ändert sich in C ++ 0x).
GCC macht nicht viele Versprechungen in Bezug auf Thread-Sicherheit und E / A. Aber die Dokumentation für das, was es verspricht, ist hier:
Das Schlüsselmaterial ist wahrscheinlich:
Ich weiß nicht, ob sich seit dem genannten 3.0-Zeitrahmen etwas geändert hat.
Die Dokumentation zur Thread-Sicherheit von MSVC für
iostreams
finden Sie hier: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :Beachten Sie, dass diese Informationen für die neueste Version von MSVC gelten (derzeit für VS 2010 / MSVC 10 /
cl.exe
16.x). Sie können die Informationen für ältere Versionen von MSVC mithilfe eines Dropdown-Steuerelements auf der Seite auswählen (und die Informationen sind für ältere Versionen unterschiedlich).quelle