Ważnym tłem jest to, że stdoutzgodnie z ustawieniami domyślnymi wymagane jest buforowanie linii przez standard.
Powoduje to \nopróżnienie wyjścia.
Ponieważ drugi przykład nie zawiera nowej linii, dane wyjściowe nie są opróżniane, a ponieważ fork()kopiuje cały proces, kopiuje również stan stdoutbufora.
Teraz te fork()wywołania w twoim przykładzie tworzą łącznie 8 procesów - wszystkie z kopią stanu stdoutbufora.
Z definicji wszystkie te procesy wywołują exit()po powrocie, main()a następnie exit()wywołania na wszystkich aktywnych strumieniach stdio . Obejmuje to, w wyniku czego widzisz tę samą treść osiem razy.fflush()fclose()stdout
Dobrą praktyką jest wywoływanie fflush()wszystkich strumieni z oczekującymi fork()danymi wyjściowymi przed wywołaniem lub zezwolenie na rozwidlone wywołanie potomne, _exit()które wychodzi z procesu bez opróżniania strumieni stdio.
Zauważ, że dzwonienie exec()nie opróżnia buforów stdio, więc nie martw się o bufory stdio, jeśli (po wywołaniu fork()) zadzwonisz exec()i (jeśli to się nie powiedzie) _exit().
BTW: Aby zrozumieć, że może to spowodować nieprawidłowe buforowanie, oto poprzedni błąd w systemie Linux, który został niedawno naprawiony:
Standard wymaga stderrdomyślnie stderrbuforowania bufora, ale Linux zignorował to i sprawił, że linia została buforowana i (jeszcze gorzej) całkowicie buforowana na wypadek, gdyby stderr został przekierowany przez potok. Więc programy napisane dla UNIXa wypisały rzeczy bez Linii zbyt późno w Linuksie.
Patrz komentarz poniżej, wydaje się, że jest to teraz naprawione.
Oto co robię, aby obejść ten problem z Linuksem:
/*
* 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);
Ten kod nie wyrządza szkody na innych platformach, ponieważ wywołanie fflush()strumienia, który został właśnie opróżniony, jest noop.
./prog1 > prog1.out) lub potoku (./prog1 | cat). Przygotuj się na zawrót głowy. :-)