stdout Thread-sicher in C unter Linux?

Lesezeit: 6 Minuten

Schreibt mit stdout printf Thread-sicher unter Linux? Was ist mit der Verwendung der unteren Ebene write Befehl?

Es ist nicht durch den C-Standard spezifiziert – es hängt von Ihrer Implementierung der C-Standardbibliothek ab. Tatsächlich erwähnt der C-Standard Threads überhaupt nicht, da bestimmte Systeme (zB eingebettete Systeme) kein Multithreading haben.

In der GNU-Implementierung (glibc), die meisten übergeordneten Funktionen in stdio, die sich damit befassen FILE* Objekte sind Thread-sicher. Diejenigen, die es normalerweise nicht sind unlocked in ihren Namen (z getc_unlocked(3)). Die Thread-Sicherheit liegt jedoch auf der Ebene der einzelnen Funktionsaufrufe: Wenn Sie mehrere Aufrufe an durchführen printf(3)zum Beispiel wird jeder dieser Aufrufe garantiert atomar ausgegeben, aber andere Threads könnten Dinge zwischen Ihren Aufrufen von ausgeben printf(). Wenn Sie sicherstellen möchten, dass eine Folge von E/A-Aufrufen atomar ausgegeben wird, können Sie sie mit einem Paar umgeben flockfile(3)/funlockfile(3) Anrufe zum Sperren der FILE handhaben. Beachten Sie, dass diese Funktionen wiedereintrittsfähig sind, sodass Sie sie sicher aufrufen können printf() zwischen ihnen, und das wird nicht einmal in Gedanken zu einem Stillstand führen printf() selbst ruft an flockfile().

Die Low-Level-E/A-Aufrufe wie z write(2) sollte Thread-sicher sein, aber da bin ich mir nicht 100% sicher – write() führt einen Systemaufruf in den Kernel durch, um I/O auszuführen. Wie genau dies geschieht, hängt davon ab, welchen Kernel Sie verwenden. Es könnte die sein sysenter Anweisung, oder die int (Unterbrechungs-)Befehl auf älteren Systemen. Sobald er sich im Kernel befindet, ist es Sache des Kernels sicherzustellen, dass die I/O Thread-sicher ist. In einem Test, den ich gerade mit der Darwin Kernel Version 8.11.1 gemacht habe, write(2) scheint Thread-sicher zu sein.

  • Diese Antwort ignoriert, dass die Frage mit Unix/Linux gekennzeichnet war. POSIX erfordert, dass stdio Thread-sicher ist, was ziemlich unglücklich ist, da es die Leistung beeinträchtigt und es keine praktische Möglichkeit gibt, mit derselben DATEI von mehreren Threads aus zu arbeiten (Daten werden hoffnungslos verschachtelt ausgegeben; Atomarität ist nur auf Zeichenebene).

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Juli 2010 um 13:46 Uhr

  • Manchmal ist es ganz in Ordnung, wenn die Ausgabe verschachtelt erfolgt, zB beim Loggen über printf aus mehreren Threads.

    – Nob

    19. Februar 2013 um 17:13 Uhr

  • @couling Ich denke, er meint, dass die Thread-Sicherheit nutzlos ist, weil sowieso alles verschachtelt wird – es sei denn, Sie verwenden ein explizites f[un]Sperrdatei sowieso.

    – Adrian Ratnapala

    1. Dezember 2013 um 6:44 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Ob Sie es “threadsicher” nennen würden, hängt von Ihrer Definition von threadsicher ab. POSIX erfordert stdio Funktionen zum Sperren verwenden, damit Ihr Programm nicht abstürzt, beschädigt die FILE Objektzustände usw., wenn Sie verwenden printf gleichzeitig aus mehreren Threads. Allerdings alle stdio Operationen werden formal durch wiederholte Aufrufe von spezifiziert fgetc und fputc, so dass keine größere Atomizität garantiert ist. Das heißt, wenn die Threads 1 und 2 versuchen zu drucken "Hello\n" und "Goodbye\n" Gleichzeitig gibt es keine Garantie dafür, dass die Ausgabe auch so sein wird "Hello\nGoodbye\n" oder "Goodbye\nHello\n". Es könnte genauso gut sein "HGelolodboy\ne\n". In der Praxis erwerben die meisten Implementierungen eine einzige Sperre für den gesamten Schreibaufruf auf höherer Ebene, einfach weil es effizienter ist, aber Ihr Programm sollte dies nicht annehmen. Es kann Ausnahmefälle geben, in denen dies nicht getan wird; Beispielsweise könnte eine Implementierung wahrscheinlich vollständig auf das Sperren von ungepufferten Streams verzichten.

Bearbeiten: Der obige Text zur Atomizität ist falsch. POSIX garantiert alles stdio Operationen sind atomar, aber die Garantie ist in der Dokumentation für versteckt flockfile: http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html

Alle Funktionen, die auf ( FILE *)-Objekte verweisen, sollen sich so verhalten, als ob sie flockfile() und funlockfile() intern verwenden, um den Besitz dieser ( FILE *)-Objekte zu erlangen.

Du kannst den … benutzen flockfile, ftrylockfileund funlockfile Funktionen selbst, um atomare Schreibvorgänge zu erreichen, die größer sind als einzelne Funktionsaufrufe.

Sie sind beide so Thread-sicher, dass Ihre Anwendung nicht abstürzt, wenn mehrere Threads sie mit demselben Dateideskriptor aufrufen. Ohne eine Sperrung auf Anwendungsebene könnte jedoch alles, was geschrieben wird, verschachtelt werden.

Benutzeravatar von a3f
a3f

C hat einen neuen Standard bekommen, seit diese Frage gestellt (und zuletzt beantwortet) wurde.

C11 bietet jetzt Multithreading-Unterstützung und behebt das Multithreading-Verhalten von Streams:

§7.21.2 Ströme

¶7 Jeder Strom hat eine zugehörige Sperre, die verwendet wird Datenrennen verhindern wenn mehrere Ausführungs-Threads auf einen Stream zugreifen, und bis beschränken die Verschachtelung von Stream-Vorgängen, die von mehreren Threads ausgeführt werden. Diese Sperre kann jeweils nur von einem Thread gehalten werden. Die Sperre ist ablaufinvariant: Ein einzelner Thread kann die Sperre zu einem bestimmten Zeitpunkt mehrmals halten.

¶8 Alle Funktionen, die die Position eines Streams lesen, schreiben, positionieren oder abfragen, sperren den Stream, bevor sie darauf zugreifen. Sie geben die dem Stream zugeordnete Sperre frei, wenn der Zugriff abgeschlossen ist.

Eine Implementierung mit C11-Threads muss also die Verwendung von printf ist Thread-sicher.

Ob Atomarität (wie in no interleaving1) garantiert ist, war mir auf den ersten Blick nicht so klar, weil die Norm davon sprach einschränken Interleaving, im Gegensatz zu verhinderndie es für Datenrennen vorgeschrieben hat.

Ich tendiere dazu garantiert zu sein. Die Norm spricht von einschränken Verschachtelung, da eine Verschachtelung, die das Ergebnis nicht ändert, immer noch zulässig ist; z.B fwrite einige Bytes, fseek zurück etwas mehr und fwrite bis zum ursprünglichen Offset, so dass beide fwrites sind Rücken an Rücken. Der Implementierung steht es frei, diese 2 nachzubestellen fwrites und führen Sie sie zu einem einzigen Schreibvorgang zusammen.


1: Siehe den durchgestrichenen Text in der Antwort von R.. als Beispiel.

Es ist Thread-sicher; printf sollte ablaufinvariant sein, und Sie werden keine Fremdheit oder Beschädigung in Ihrem Programm verursachen.

Sie können nicht garantieren, dass Ihre Ausgabe von einem Thread nicht auf halbem Weg durch die Ausgabe eines anderen Threads beginnt. Wenn Ihnen das wichtig ist, müssen Sie Ihren eigenen gesperrten Ausgabecode entwickeln, um Mehrfachzugriff zu verhindern.

  • Alle Aufrufe von printf verwenden wahrscheinlich denselben Puffer, um die Zeichenfolge zu erstellen. Viele Implementierungen teilen sich auch einen Puffer zwischen scanf und printf – was einige seltsame debugabhängige Fehler verursachen kann.

    – Martin Beckett

    22. Januar 2009 um 4:04 Uhr

  • Ich weiß nicht, was andere tun, aber die GNU C-Bibliothek ist standardmäßig Thread-sicher, also wird sie nicht denselben Puffer verwenden.

    – Adam Hawes

    22. Januar 2009 um 21:54 Uhr

  • Ich denke nicht printf wiedereintrittsfähig ist, siehe stackoverflow.com/questions/3941271/…

    – Yu Hao

    3. Juni 2013 um 6:05 Uhr

  • Alle Aufrufe von printf verwenden wahrscheinlich denselben Puffer, um die Zeichenfolge zu erstellen. Viele Implementierungen teilen sich auch einen Puffer zwischen scanf und printf – was einige seltsame debugabhängige Fehler verursachen kann.

    – Martin Beckett

    22. Januar 2009 um 4:04 Uhr

  • Ich weiß nicht, was andere tun, aber die GNU C-Bibliothek ist standardmäßig Thread-sicher, also wird sie nicht denselben Puffer verwenden.

    – Adam Hawes

    22. Januar 2009 um 21:54 Uhr

  • Ich denke nicht printf wiedereintrittsfähig ist, siehe stackoverflow.com/questions/3941271/…

    – Yu Hao

    3. Juni 2013 um 6:05 Uhr

1407530cookie-checkstdout Thread-sicher in C unter Linux?

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

Privacy policy