Зауважу, що <system.h>
це нестандартний заголовок; Я замінив його на<unistd.h>
і код скомпільовано чисто.
Коли вихідні дані вашої програми надходять на термінал (екран), вона буферизується. Коли вихідні дані вашої програми надходять у конвеєр, вона повністю буферизується. Ви можете керувати режимом буферизації за допомогою функції Standard 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 );
Аналіз:
- Копіює "Привіт, мій pid 1234" у буфер для стандартного виводу. Оскільки в кінці немає нового рядка, а вихід працює в буферному режимі (або повнобуферному режимі), на терміналі нічого не відображається.
- Дає нам два окремі процеси, з абсолютно однаковим матеріалом у буфері stdout.
- Дитина має
pid == 0
і виконує рядки 4 і 5; у батьків є ненульове значення для pid
(одна з небагатьох відмінностей між двома процесами - повертаються значення з getpid()
і getppid()
ще два).
- Додає новий рядок та "Мені було роздвоєно!: D" до вихідного буфера дочірньої організації. Перший рядок виводу з'являється на терміналі; решта утримується в буфері, оскільки висновок буферизується рядком.
- Все зупиняється на 3 секунди. Після цього дитина нормально виходить через повернення в кінці основного. У цей момент залишкові дані в буфері stdout видаляються. Це залишає вихідне положення в кінці рядка, оскільки нового рядка немає.
- Сюди приходить батько.
- Батьки чекають, поки дитина закінчить вмирати.
- Батько додає новий рядок і "1345 був роздвоєний!" до вихідного буфера. Новий рядок видаляє повідомлення "Привіт" на вихід після неповного рядка, згенерованого дочірнім об'єктом.
Тепер батько зазвичай виходить через повернення в кінці основного, а залишкові дані стираються; оскільки в кінці все ще немає нового рядка, позиція курсору стоїть після знака оклику, і на цьому ж рядку з'являється підказка оболонки.
Я бачу:
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:
Зверніть увагу, що коли вихідні дані надходять на термінал, вони буферизуються, тому рядок "Привіт" з'являється перед, fork()
і там була лише одна копія. Коли вихід виводиться по трубопроводі cat
, він повністю буферизується, тому ніщо не з'являється перед fork()
і обидва процеси мають у буфері рядку "Hello", який потрібно очистити.