Зауважу, що <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", який потрібно очистити.