Замечу, что <system.h>
- нестандартный заголовок; Я заменил его на <unistd.h>
и код скомпилирован чисто.
Когда выходные данные вашей программы поступают на терминал (экран), они буферизуются. Когда вывод вашей программы поступает в канал, он полностью буферизуется. Вы можете управлять режимом буферизации с помощью стандартных функций C setvbuf()
и _IOFBF
(полная буферизация), _IOLBF
(линейная буферизация) и _IONBF
(без буферизации).
Вы могли бы продемонстрировать это в своей пересмотренной программе, отправив вывод вашей программы, скажем, на cat
. Даже с символами перевода строки в конце строки printf()
вы увидите двойную информацию. Если вы отправите его прямо в терминал, то увидите только одну партию информации.
Мораль этой истории - быть осторожным, чтобы вызвать fflush(0);
, чтобы очистить все буферы ввода / вывода перед разветвлением.
Строчный анализ в соответствии с запросом (фигурные скобки и т. Д. Удалены, а ведущие пробелы удалены редактором разметки):
printf( "Hello, my pid is %d", getpid() );
pid = fork();
if( pid == 0 )
printf( "\nI was forked! :D" );
sleep( 3 );
else
waitpid( pid, NULL, 0 );
printf( "\n%d was forked!", pid );
Анализ:
- Копирует "Hello, my pid 1234" в буфер для стандартного вывода. Поскольку в конце нет новой строки и вывод работает в режиме буферизации строки (или режиме полной буферизации), на терминале ничего не появляется.
- Дает нам два отдельных процесса с абсолютно одинаковым материалом в буфере stdout.
- Ребенок имеет
pid == 0
и выполняет строки 4 и 5; родительский элемент имеет ненулевое значение для pid
(одно из немногих различий между двумя процессами - возвращаемые значения из getpid()
и getppid()
- еще два).
- Добавляет перевод строки и «меня разветвляют!: D» в выходной буфер дочернего элемента. Первая строка вывода появляется на терминале; остальное хранится в буфере, так как вывод буферизуется в строке.
- Все останавливается на 3 секунды. После этого ребенок выходит нормально через возврат в конце main. В этот момент остаточные данные в буфере stdout сбрасываются. Это оставляет позицию вывода в конце строки, так как нет новой строки.
- Родитель приходит сюда.
- Родитель ждет, когда ребенок умрет.
- Родитель добавляет новую строку и "1345 был разветвлен!" в выходной буфер. Новая строка сбрасывает сообщение «Hello» на выход после неполной строки, сгенерированной дочерним элементом.
Родитель теперь нормально завершается через возврат в конце main, а остаточные данные сбрасываются; поскольку в конце по-прежнему нет новой строки, позиция курсора находится после восклицательного знака, а подсказка оболочки отображается в той же строке.
То, что я вижу:
Osiris-2 JL: ./xx
Hello, my pid is 37290
I was forked! :DHello, my pid is 37290
37291 was forked!Osiris-2 JL:
Osiris-2 JL:
Номера PID разные, но общий вид ясен. Добавление новых строк в конце операторов printf()
(что очень быстро становится стандартной практикой) сильно меняет вывод:
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
printf( "Hello, my pid is %d\n", getpid() );
pid = fork();
if( pid == 0 )
printf( "I was forked! :D %d\n", getpid() );
else
{
waitpid( pid, NULL, 0 );
printf( "%d was forked!\n", pid );
}
return 0;
}
Теперь я получаю:
Osiris-2 JL: ./xx
Hello, my pid is 37589
I was forked! :D 37590
37590 was forked!
Osiris-2 JL: ./xx | cat
Hello, my pid is 37594
I was forked! :D 37596
Hello, my pid is 37594
37596 was forked!
Osiris-2 JL:
Обратите внимание, что когда вывод поступает на терминал, он буферизуется строкой, поэтому строка «Hello» появляется перед fork()
, и была только одна копия. Когда вывод передается по каналу cat
, он полностью буферизуется, поэтому перед fork()
ничего не появляется, и оба процесса имеют строку «Hello» в буфере для очистки.