Строки 63–67 обрабатывают случай, когда затребованный потомок недоступен. В этом случае возвращается значение 0, поэтому выводится сообщение, и выполнение продолжается.
Строки 68–70 обрабатывают случай, при котором был прерван системный вызов. В этом случае самым подходящим способом обработки является
goto
обратно на вызов
waitpid
. (Поскольку
main
блокирует все сигналы при вызове обработчика сигнала [строка 96], это прерывание не должно случиться. Но этот пример показывает, как обработать все случаи.)
Строки 71–76 обрабатывают любую другую ошибку, выводя соответствующее сообщение
об ошибке.
81 /* main --- установка связанных с порожденными процессами сведений и сигналов, создание порожденных процессов */
82
83 int main(int argc, char **argv)
84 {
85 struct sigaction sa;
86 sigset_t childset, emptyset;
87 int i;
88
89 for (i = 0; i < nkids; i++)
90 kids[i] = NOT_USED;
91
92 sigemptyset(&emptyset);
93
94 sa.sa_flags =
SA_NOCLDSTOP;
95 sa.sa_handler = childhandler;
96 sigfillset(&sa.sa_mask); /* блокировать все при вызове обработчика */
97 sigaction(SIGCHLD, &sa, NULL);
98
99 sigemptyset(&childset);
100 sigaddset(&childset, SIGCHLD);
101
102 sigprocmask(SIG_SETMASK, &childset, NULL); /* блокировать его в коде main */
103
104 for (nkids = 0; nkids < 5; nkids++) {
105 if ((kids[nkids] = fdrk) == 0) {
106 sleep(3);
107 _exit(0);
108 }
109 }
110
111 sleep(5); /* дать потомкам возможность завершения */
112
113 printf("waiting for signal\n");
114 sigsuspend(&emptyset);
115
116 return 0;
117 }
Строки 89–90 инициализируют
kids
. Строка 92 инициализирует
emptyset
. Строки 94–97 настраивают и устанавливают обработчик сигнала для
SIGCHLD
. Обратите внимание на использование в строке 94
SA_NOCLDSTOP
, тогда как строка 96 блокирует все сигналы при вызове обработчика.
Строки 99–100 создают набор сигналов, представляющих
SIGCHLD
, а строка 102 устанавливает их в качестве маски сигналов процесса для программы.
Строки 104–109 создают пять порожденных процессов, каждый из которых засыпает на три секунды. По ходу дела они обновляют массив
kids
и переменную
nkids
.
Строка 111 дает затем потомкам шанс завершиться, заснув на еще больший промежуток времени. (Это не гарантирует, что
порожденные процессы завершатся, но шансы довольно велики.)
Наконец, строки 113–114 выводят сообщение и приостанавливаются, заменив маску сигналов процесса, блокирующую
SIGCHLD
, пустой маской. Это дает возможность появиться сигналу
SIGCHLD
, что в свою очередь вызывает запуск обработчика сигнала. Вот что происходит:
$ ch10-reap1 /* Запуск программы */
waiting for signal
Entered childhandler
reaped process 23937
reaped process 23938
reaped process 23939
reaped process 23940
reaped process 23941
Exited childhandler
Обработчик сигнала собирает сведения о потомках за один проход.
Следующая программа,
ch10-reap2.c
, сходна с
ch10-reap1.c
. Разница в том, что она допускает появление сигнала
SIGCHLD
в любое время. Такое поведение увеличивает шанс получения более одного
SIGCHLD
, но не гарантирует это. В результате обработчик сигнала все равно должен быть готов обработать в цикле несколько потомков.
1 /* ch10-reap2.c — демонстрирует управление SIGCHLD, один сигнал на потомка */