#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 относится к методу программирования, который включает копирование-вставку кода без полного понимания того, как это работает. Они знают, что определенный сегмент кода выполняет определенную задачу, но не обязательно, как или почему. Это происходит от — я хочу сказать — войны во Вьетнаме, когда страны создавали аэродромы для обеспечения своих военных действий. Коренные жители поняли, что на эти аэродромы будут доставляться грузы, поэтому они попытались построить свои собственные реплики аэродромов и самолетов из соломы в надежде, что это приведет к появлению грузовых самолетов. Они стали известны как культы груза .