Чи існує якийсь варіант UNIX, на якому дочірній процес помирає разом із батьком?


41

Я вивчаю поведінку ядра Linux вже досить давно, і мені завжди було зрозуміло, що:

Коли процес вмирає, всі його діти повертаються до initпроцесу (PID 1), поки вони зрештою не загинуть.

Однак нещодавно хтось із набагато більшим досвідом, ніж я, з ядром, сказав мені:

Коли процес закінчується, всі його діти також вмирають (якщо ви не використовуєте NOHUPв такому випадку вони повертаються init).

Тепер, хоча я не вірю в це, я все-таки написав просту програму, щоб переконатися в цьому. Я знаю, що не слід покладатися на час ( sleep) для тестів, оскільки все залежить від планування процесу, але для цього простого випадку я думаю, що це досить.

int main(void){
    printf("Father process spawned (%d).\n", getpid());
    sleep(5);

    if(fork() == 0){
        printf("Child process spawned (%d => %d).\n", getppid(), getpid());
        sleep(15);
        printf("Child process exiting (%d => %d).\n", getppid(), getpid());
        exit(0);
    }

    sleep(5);
    printf(stdout, "Father process exiting (%d).\n", getpid());
    return EXIT_SUCCESS;
}

Ось результат програми з відповідним psрезультатом щоразу, коли printfйдеться:

$ ./test &
Father process spawned (435).

$ ps -ef | grep test
myuser    435    392   tty1    ./test

Child process spawned (435 => 436).

$ ps -ef | grep test
myuser    435    392   tty1    ./test
myuser    436    435   tty1    ./test

Father process exiting (435).

$ ps -ef | grep test
myuser    436    1     tty1    ./test

Child process exiting (436).

Зараз, як бачите, це поводиться так, як я б очікував. Сиротичний процес (436) повертається до init(1), поки він не вмирає.

Однак чи існує система на основі UNIX, до якої ця поведінка не застосовується за замовчуванням? Чи існує якась система, за якою загибель процесу негайно спричиняє смерть усіх її дітей?

Відповіді:


68

Коли процес закінчується, всі його діти також вмирають (якщо ви не використовуєте NOHUP, і в цьому випадку вони повертаються до init).

Це неправильно. Мертві неправильно. Людина, яка сказала, що або помилилася, або переплутала певну ситуацію із загальною справою.

Є два способи, за якими загибель процесу може опосередковано спричинити смерть його дітей. Вони пов'язані з тим, що відбувається, коли термінал закритий. Коли термінал зникає (історично тому, що послідовна лінія була розірвана через вивільнення модему, в наш час зазвичай через те, що користувач закрив вікно емулятора терміналу), сигнал SIGHUP надсилається до керуючого процесу, що працює в цьому терміналі - як правило, починається початкова оболонка в цьому терміналі. Раковини зазвичай на це реагують, виходячи. Перш ніж виходити, снаряди, призначені для інтерактивного використання, надсилають HUP на кожну роботу, яку вони розпочали.

Початок завдання з оболонки з nohupперервами, що друге джерело HUP сигналізує, тому що завдання буде ігнорувати сигнал і, таким чином, не буде сказано померти, коли термінал зникне. Інші способи переривання розповсюдження сигналів HUP з оболонки на завдання включають використання disownвбудованої оболонки, якщо у неї є така (завдання видалено зі списку завдань оболонки) та подвійне форкінг (оболонка запускає дитину, яка запускає дитину власне і виходить негайно; оболонка не знає онука).

Знову ж таки, завдання, розпочаті в терміналі, гинуть не тому, що їх батьківський процес (оболонка) гине, а тому, що їх батьківський процес вирішує вбити їх, коли йому сказано вбити їх. І початкова оболонка в терміналі гине не тому, що її батьківський процес гине, а тому, що його термінал зникає (що може бути, а може і не випадково, тому що термінал надається емулятором терміналу, який є батьківським процесом оболонки).


1
Є третій спосіб - щось із контрольними групами. Все, що я знаю, - це те, що systemd використовує це для примусового вбивства.
o11c

5
@JanHudec Я думаю , ти плутаєш nohupз disown. disownце вбудована в деяку оболонку, яка видаляє запущену роботу з таблиці завдань (беручи такий аргумент %1), і головний корисний побічний ефект цього полягає в тому, що оболонка не буде надсилати SIGHUP до підпроцесу. nohupце зовнішня утиліта, яка ігнорує SIGHUP (і робить деякі інші речі), а потім запускає команду, передану в її командному рядку.
Жил "ТАК - перестань бути злим"

@Gilles: Ні, я не був, але, дивлячись на strace, nohupнасправді ігнорує сигнал, перш ніж він execбуде командою.
Ян Худек

Спасибі за вашу відповідь! Мені особливо сподобалося небагато історичного підґрунтя, що стосується модемних зупинок. Я почав хвилюватися, що я весь цей час нерозумів ядро ​​...
Джон У. Сміт

3
Також слід зазначити, що програма закривається, коли вона отримує SIGHUP, оскільки обробник сигналу за замовчуванням для SIGHUP - це вихід. Але будь-яка програма може реалізувати власний обробник SIGHUP, що може призвести до того, що він не вийде, коли батьківська оболонка надсилає йому SIGHUP.
slebetman

12

Коли процес закінчується, всі його діти також вмирають (якщо ви не використовуєте NOHUP, і в цьому випадку вони повертаються до init).

Це правильно, якщо процес є лідером сесії. Коли ведучий сесії помирає, SIGHUP надсилається всім учасникам сеансу. На практиці це означає його дітей та їхніх нащадків.

Процес робить себе лідером сеансу за допомогою виклику setsid. Раковини це використовують.


Я щойно провів тест з цього приводу, але я не міг відтворити поведінку, яку ви описуєте ... Я породив процес, дав йому новий сеанс ( fork, вбийте батьківський процес, setsid) і відправив іншу дитину на цю нову сесію. Однак, коли батьківський процес (новий керівник сесії) загинув, дитина не отримала SIGHUP і приєдналася initдо нього, поки він врешті-решт не закінчився.
Джон У. Сміт

З setpgid(2)набору сторінки: Якщо сеанс має керуючий термінал, а прапор CLOCAL для цього терміналу не встановлений, і відбувається зависання терміналу, тоді лідеру сеансу надсилається SIGHUP. Якщо ведучий сеансу виходить, то сигнал SIGHUP також буде відправлений до кожного процесу в групі процесу переднього плану керуючого терміналу.
ніндзя

1
@ninjalj Тоді я здогадуюсь, що ця відповідь є дійсною лише тоді, коли керівник сесії є також контрольним процесом терміналу. Стандартний ведучий сесії, незалежний від будь-якого терміналу, не вбиває своїх дітей. Це правильно?
Джон У. Сміт

-1

Тож, про що говорять вище плакати, діти не вмирають, батько вбиває їх (або надсилає їм сигнал, на який вони припиняються). Таким чином, ви можете мати те, що ви просите, якщо ви запрограмуєте Батька (1) вести облік усіх своїх дітей та (2) надсилати сигнал усім своїм дітям.

Це те, що робить Шелл, і це має бути тим, що робить ваш батьківський процес. Можливо, буде потрібно ввімкнути сигнал HUP у батьків, щоб ви все ще мали достатній контроль, щоб вбити дітей.


Багато причин можуть змусити батьків померти. Не існує жодного способу запобігти виживанню дітей, якщо, наприклад, батько SIGKILLed.
Еміль Йерабек підтримує Моніку

-1

Я пропускаю один біт у відповідях, який трохи пов'язаний з помираючими батьками: коли процес пише на трубі, для якої вже немає процесу читання, він отримує ЗНАЧЕННЯ. Стандартна дія для SIGPIPE - це припинення.

Це дійсно може призвести до вмирання процесів. Насправді це стандартний спосіб, коли програма yesгине.

Якщо я страчу

(yes;echo $? >&2)|head -10

у моїй системі відповідь така

y
y
y
y
y
y
y
y
y
y
141

і 141 дійсно 128 + ПІДПРИЄМСТВО:

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers

з man 7 signal.


2
Але процес зчитування з труби не обов'язково (або навіть зазвичай) його батьківський. Тож це справді зовсім інший випадок від того, про що задається питання.
Бармар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.