fork () - Как заставить последнего потомка убить процесс отца / происхождения?

Я хотел бы сделать последним дочерним элементом из числа N детей (созданных вилкой), чтобы убить своего отца.

Я пытался :

в функции вилки

signal(SIGINT, processKilled);
int car_finished = 0;

for (int car = 0; car < CAR; car++) {
     int pid = fork();
     ...
}

в сыне

car_finished++;
    if (car_finished == CAR-1){
        kill(getppid(), SIGKILL);
    }
    exit(EXIT_SUCCESS);

но последний ребенок отца не убивает ....

Как я могу это сделать ? я понятия не имею.


person Guillaume Lemer    schedule 14.12.2019    source источник
comment
Может быть, будет яснее, если вы вставите свой реальный код, а не разбиваете его на две части, но если вы увеличиваете car_finished в дочернем процессе, это повлияет на дочернюю копию car_finished, а не на родительскую. Таким образом, в любом потомке его значение никогда не будет больше 1.   -  person Graeme Cole    schedule 14.12.2019
comment
Может быть, использовать getpid() перед циклом for, в котором вы вызываете fork, и просто использовать это? (Кроме того, несколько более устоявшаяся терминология относится к дочерним и родительским процессам, а не к сыну / дочери и / или отцу / матери.)   -  person gstukelj    schedule 14.12.2019
comment
Хороший вопрос, кстати. Вы должны превратить это в свой вопрос.   -  person RobertS supports Monica Cellio    schedule 14.12.2019


Ответы (1)


Ваша проблема была правильно диагностирована Грэмом Коулом в комментарий:

  • Каждый дочерний элемент имеет свою собственную копию car_finished, поэтому счетчик в любом дочернем элементе всегда достигает только 1, поэтому, если существует более одного дочернего элемента, сигнал никогда не отправляется.

Как это решить?

Вы можете использовать общую память и поместить car_finished в общую память. Однако вам придется синхронизировать доступ к общей памяти между процессами, поэтому это быстро становится громоздким (при условии, что это не считалось громоздким, когда упоминалась общая память).

Возможно, можно будет использовать файл для подсчета дочерних элементов. Потомки будут использовать (рекомендательную) блокировку файла для предотвращения одновременного доступа, и каждый из них будет уменьшать счетчик перед выходом, а тот, который уменьшает счетчик до нуля, удаляет файл и отправляет сигнал родительскому процессу. Это довольно надежно, но не так быстро (но, вероятно, будет достаточно быстро). Основная проблема возникает, если дочерний процесс завершается без уменьшения счетчика (например, из-за сбоя с ошибкой памяти или отправки SIGKILL). Тогда счетчик никогда не станет равным нулю, поэтому родительский элемент никогда не получит сигнал.

Если родитель просто ждет смерти детей, он должен выполняться в wait() цикле:

int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
    /* …optionally… */
    printf("%d: PID %d exited with status 0x.4X\n", (int)getpid(), corpse, status);
}
exit(EXIT_SUCCESS);

Если родитель выполняет некоторую обработку, дочерний элемент не должен отправлять SIGKILL; это не дает родителям времени на уборку. Каждый дочерний элемент может отправить родительскому элементу сигнал SIGUSR1, а обработчик родительского сигнала может подсчитать количество полученных сигналов и выйти, когда он получит их все. Это сложнее продемонстрировать полностью, но для настройки обработчика сигналов используется sigaction().

Иногда родитель может создать канал, закрыть конец записи и попытаться прочитать из него. Каждый дочерний элемент закрывал бы конец канала для чтения при его запуске (гигиена кода - это можно опустить). Когда дочерний элемент завершен, он завершает работу, явно или неявно закрывая конец записи канала. Когда последний дочерний элемент выйдет из read(), родитель получит возврат «нулевое прочтение байтов» и может закрыть канал (или просто завершить работу).

Эти последние решения полагаются на сотрудничество родительского процесса. Обычно это беспроигрышный вариант (если семья не является неблагополучной, родитель по мере возможности помогает своим детям).

person Jonathan Leffler    schedule 14.12.2019
comment
Я использовал общую память для решения своей проблемы, потому что это было проще для меня. Спасибо за ваше время и за то, что помогли мне понять, в чем проблема. - person Guillaume Lemer; 16.12.2019