Важным фоном здесь является то, что стандарт stdout
должен быть буферизован линией по умолчанию.
Это приводит \n
к сбросу вывода.
Поскольку второй пример не содержит символ новой строки, выходные данные не сбрасываются и, поскольку fork()
копирует весь процесс, он также копирует состояние stdout
буфера.
Теперь эти fork()
вызовы в вашем примере создают в общей сложности 8 процессов - все они с копией состояния stdout
буфера.
По определению, все эти процессы вызывают exit()
при возврате из, main()
а затем exit()
вызовы во всех активных потоках stdio . Это включает в себя, и в результате вы видите один и тот же контент восемь раз.fflush()
fclose()
stdout
Хорошей практикой является вызов fflush()
всех потоков с ожидающим выводом перед вызовом fork()
или явное разрешение разветвленного дочернего вызова, _exit()
который только завершает процесс, не сбрасывая потоки stdio.
Обратите внимание, что вызов exec()
не очищает буферы stdio, поэтому нормально не заботиться о буферах stdio, если вы (после вызова fork()
) вызываете exec()
и (если это не удается) вызываете _exit()
.
КСТАТИ: Чтобы понять, что неправильная буферизация может вызвать, вот старая ошибка в Linux, которая была недавно исправлена:
Стандарт требует stderr
отмены stderr
буферизации по умолчанию, но Linux проигнорировал это и сделал буферизацию строки и (что еще хуже) полную буферизацию в случае, если stderr был перенаправлен через канал. Так что программы, написанные для UNIX, выводили вещи без перевода строки в Linux слишком поздно.
См. Комментарий ниже, кажется, сейчас исправлено.
Вот что я делаю, чтобы обойти эту проблему Linux:
/*
* 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);
Этот код не наносит вреда на других платформах, так как вызов fflush()
только что очищенного потока является пустым занятием.
./prog1 > prog1.out
) или канал (./prog1 | cat
). Приготовьтесь к тому, что ваш разум будет взорван :-)