waiting for signals
Entered childhandler /* Обработчик сигнала вызван лишь однажды */
reaped process 9564
reaped process 9565
reaped process 9566
reaped process 9567
reaped process 9568
Exited childhandler
ЗАМЕЧАНИЕ. В коде для ch10-reap2.c
есть один важный дефект — состояние гонки. Взгляните еще раз на строки 106–112 в ch10-reap2.c
. Что случится, если SIGCHLD
появится при исполнении этого кода? Массив kids
и переменные nkids
и kidsleft
могут оказаться разрушенными: код в main
добавляет новый процесс, но обработчик сигнала вычитает один.
Этот пример кода является отличным примером критического раздела; он не должен прерываться при исполнении. Правильным способом работы с этим кодом является заключение его между вызовами, которые сначала блокируют, а затем разблокируют SIGCHLD
.
10.8.3.3. Строгий родительский контроль
Структура siginfo_t
и перехватчик сигнала с тремя аргументами дают возможность узнать, что случилось с потомком. Для SIGCHLD поле si_code
структуры siginfo_t
указывает причину посылки сигнала (остановка, возобновление, завершение порожденного процесса и т.д.). В табл. 10.5 представлен полный список значений. Все они определены в качестве расширения XSI стандарта POSIX.
Следующая программа, ch10-status.c
, демонстрирует использование структуры siginfo_t
.
1 /* ch10-status.c --- демонстрирует управление SIGCHLD, используя обработчик с 3 аргументами */
2
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 void manage(siginfo_t *si);
11
/* ...не изменившийся для format_num() код опущен... */
Таблица 10.5. Значения si_code
XSI для SIGCHLD
Значение | Смысл |
---|---|
CLD_CONTINUED | Остановленный потомок был возобновлен. |
CLD_DUMPED | Потомок завершился с ошибкой, создан образ процесса |
CLD_EXITED | Потомок завершился нормально. |
CLD_KILLED | Потомок был завершен сигналом |
CLD_STOPPED | Порожденный процесс был остановлен. |
CLD_TRAPPED | Трассируемый потомок остановлен (Это условие возникает, когда программа трассируется — либо из отладчика, либо для мониторинга реального времени В любом случае, вы вряд ли увидите его в обычных ситуациях.) |
Строки 3–8 включают стандартные заголовочные файлы, строка 10 объявляет manage()
, которая имеет дело с изменениями состояния потомка, а функция format_num()
не изменилась по сравнению с предыдущим.
37 /* childhandler --- перехват SIGCHLD, сбор данных лишь об одном потомке */
38
39 void childhandler(int sig, siginfo_t *si, void *context)
40 {
41 int status, ret;
42 int i;
43 char buf[100];
44 static const char entered[] = "Entered childhandler\n";
45 static const char exited[] = "Exited childhandler\n";
46
47 write(1, entered, strlen(entered));
48 retry:
49 if ((ret = waitpid(si->si_pid, &status, WNOHANG)) == si->si_pid) {
50 strcpy(buf, "\treaped process ");
51 strcat(buf, format_num(si->si_pid));
52 strcat(buf, "\n");
53 write(1, buf, strlen(buf));