Der wichtige Hintergrund hierbei ist, dass stdout
die Leitung standardmäßig gepuffert sein muss .
Dies bewirkt, dass a \n
den Ausgang spült.
Da das zweite Beispiel keine neue Zeile enthält, wird die Ausgabe nicht geleert und fork()
kopiert als Kopie des gesamten Prozesses auch den Zustand des stdout
Puffers.
Mit diesen fork()
Aufrufen in Ihrem Beispiel werden insgesamt 8 Prozesse erstellt - alle mit einer Kopie des Status des stdout
Puffers.
Per Definition rufen alle diese Prozesse exit()
bei der Rückkehr von main()
und bei exit()
Aufrufen fflush()
gefolgt von fclose()
allen aktiven stdio- Streams auf. Dies schließt ein stdout
und als Ergebnis wird derselbe Inhalt achtmal angezeigt.
Es ist empfehlenswert, vor dem Aufrufen fflush()
alle Streams mit ausstehender Ausgabe aufzurufen fork()
oder den untergeordneten Zweig explizit aufrufen zu lassen, der _exit()
den Prozess nur beendet, ohne die stdio-Streams zu leeren.
Beachten Sie, dass beim Aufrufen exec()
die Stdio-Puffer nicht geleert werden. Daher ist es in Ordnung, sich nicht um die Stdio-Puffer zu kümmern, wenn Sie (nach dem Aufrufen fork()
) anrufen exec()
und (falls dies fehlschlägt) anrufen _exit()
.
Übrigens: Um zu verstehen, dass eine falsche Pufferung dazu führen kann, ist hier ein früherer Fehler in Linux, der kürzlich behoben wurde:
Der Standard muss stderr
standardmäßig nicht stderr
gepuffert sein , aber Linux hat dies ignoriert und die Zeilen gepuffert und (noch schlimmer) vollständig gepuffert, falls stderr über eine Pipe umgeleitet wurde. Programme, die für UNIX geschrieben wurden, gaben also unter Linux Dinge ohne Zeilenumbruch zu spät aus.
Siehe Kommentar unten, es scheint jetzt behoben zu sein.
Folgendes tue ich, um dieses Linux-Problem zu umgehen:
/*
* Linux comes with a broken libc that makes "stderr" buffered even
* though POSIX requires "stderr" to be never "fully buffered".
* As a result, we would get garbled output once our fork()d child
* calls exit(). We work around the Linux bug by calling fflush()
* before fork()ing.
*/
fflush(stderr);
Dieser Code schadet auf anderen Plattformen nicht, da das Aufrufen fflush()
eines gerade gelöschten Streams ein Noop ist.
./prog1 > prog1.out
) oder eine Pipe (./prog1 | cat
) auszuführen . Bereite dich darauf vor, deinen Verstand durchzubrennen. :-)