Как родительский процесс может узнать, был ли завершен дочерний процесс?

#c #parallel-processing #fork #parent-child

#c #параллельная обработка #fork #родитель-потомок

Вопрос:

Я хочу написать программу, в которой родитель создает ровно 1 дочерний процесс. Дочерний процесс должен вывести свой pid в стандартный вывод, а затем завершить. Родительский процесс должен ждать, пока не будет уверен, что дочерний процесс завершен. Родительский процесс завершается после того, как он дождался дочернего процесса.

Это то, что у меня есть до сих пор:

 #include <unistd.h>     
#include <stdlib.h> 
#include <stdio.h>

int main(void) 
{ 
    int child;
    child = fork();
    if (child == 0)
        {
            printf("Child process has PID: %d. n", getpid());
            exit(0);    
        }

        // how can the parent process find out it the child process was terminated successful? 

        printf("Child process terminated successfullyn");
        return EXIT_SUCCESS;

} 


  

Как родительский процесс может узнать, был ли завершен дочерний процесс? Я не могу использовать wait() или waitpid() в этой программе.

Спасибо за вашу помощь!

Комментарии:

1. посмотрите на сигнал SIGCHLD

2. Просто для ясности, почему вы не можете использовать wait или waitpid ? Это нормальное решение этой проблемы.

3. @DanielPryden очевидно, что операция не хочет блокироваться, решение заключается в использовании SIGCHILD

4. Конечно, родитель хочет, чтобы его заблокировали, @bruno. Нет другой разумной интерпретации «Родительский процесс должен ожидать [так в оригинале], пока не будет уверен, что дочерний процесс завершен» (курсив добавлен).

5. @JohnBollinger Я говорю это из-за окончания вопроса после кода. Не говорите мне, что вы никогда не внедряли процессы запуска менеджера и где вы не хотите, чтобы вас блокировали, даже управляя завершением дочернего процесса. почему мне часто кажется, что вы просто собираетесь противоречить мне или убить меня? Я действительно устал от этого!

Ответ №1:

Когда дочерний процесс завершается, родительскому процессу отправляется сигнал SIGCHLD, по умолчанию родительский процесс игнорирует SIGCHLD, однако вы можете зарегистрировать обработчик сигнала, который будет его перехватывать.

Вам нужно быть осторожным в том, что вы делаете в обработчике сигналов — довольно много стандартных функций небезопасны в использовании.

Подход SIGCHLD появляется в коде, когда у родителя есть своя работа, и он не может просто ждать дочернего элемента. Если родитель просто порождает дочерние элементы, а затем ждет их завершения, наилучшим решением являются wait() и waitpid().

Наконец, если вы не вызываете wait() или waitpid(), вы рискуете создать процесс-зомби, дочерний процесс ожидает, что его родительский процесс получит статус завершения через вызов одной из этих функций.

Комментарии:

1. На самом деле я думаю, что существует SIGCHLD обработчик по умолчанию, который используется при реализации wait , по крайней мере, в некоторых операционных системах?

Ответ №2:

Как я сказал в примечании, используйте, например, сигнал SIGCHLD :

 #include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void handler(int sig)
{
  pid_t chpid = wait(NULL);

  /* WARNING : to show the call of the handler, do not do that
     in a 'real' code, we are in a handler of a signal */
  printf("Child pid %d ended (signal %s)n", chpid, sig); 

  /* does 'something' to allow the parent to know chpid 
     terminated in a way compatible with parent requirement */
}

int main(void)
{
  signal(SIGCHLD, handler);

  if (!fork())
  {
    printf("Child pid is %dn", getpid());
    sleep(1);
    return 0;
  }
  printf("Parent pid is %dn", getpid());
  getchar();

  return 0;
}
  

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

Компиляция и выполнение :

 pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra s.c
pi@raspberrypi:/tmp $ ./a.out
Parent pid is 21743
Child pid is 21744
Child pid 21744 ended (signal 17)
<enter>
pi@raspberrypi:/tmp $ 
  

Конечно, сигнал 17 является SIGCHLD, потому что это единственный, который программа улавливает

Комментарии:

1. printf() — это одна из тех стандартных функций, которые вы не должны использовать в обработчике сигналов. Лучший подход — установить флаг в обработчике сигнала, а затем выполнять цикл в основном коде, пока флаг не будет установлен. На странице руководства signal должны быть перечислены разрешенные функции.

2. На самом деле никому не помогает раздавать полные решения академических упражнений.

3. @bruno Это может быть использовано для обучения некоторых людей, но это также может привести к программированию культа карго.

4. @Бруно, смысл инструктора, ставящего упражнение, в том, чтобы ученик решал его самостоятельно . Процесс разработки решения обеспечивает большую часть образовательной ценности. Если бы это было иначе, то не было бы никаких упражнений, только примеры для изучения.

5. @bruno Cargo Cult относится к методу программирования, который включает копирование-вставку кода без полного понимания того, как это работает. Они знают, что определенный сегмент кода выполняет определенную задачу, но не обязательно, как или почему. Это происходит от — я хочу сказать — войны во Вьетнаме, когда страны создавали аэродромы для обеспечения своих военных действий. Коренные жители поняли, что на эти аэродромы будут доставляться грузы, поэтому они попытались построить свои собственные реплики аэродромов и самолетов из соломы в надежде, что это приведет к появлению грузовых самолетов. Они стали известны как культы груза .