Linux программирование в примерах
Шрифт:
pid 2705 not available yet
pid 2706 not available yet
Exited childhandler
waiting for signals
Entered childhandler
reaped process 2705
pid 2706 not available yet
Exited childhandler
waiting for signals
Entered childhandler
reaped process 2706
Exited childhandler
В данном примере на каждый
SIGCHLD
! Хотя это прекрасно и полностью воспроизводимо на этой системе, это также необычно. Как на более раннем, так и на более позднем ядре и на Solaris программа получает один сигнал для более чем одного потомка:
$ uname -a /* Отобразить версию системы */
Linux example2 2.4.22-1.2115.npt1 #1 Wed Oct 29 15:42:51 EST 2003 i686 i686 i386 GNU/Linux
$ ch10-reap2 /* Запуск программы */
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 <stdio.h>
4 #include <errno.h>
5 #include <signal.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
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));
54 manage(si); /* обработать то, что произошло */
55 } else if (ret > 0) {
56 strcpy(buf, "\treaped unexpected pid ");
57 strcat(buf, format_num(ret));
58 strcat(buf, "\n");
59 write(1, buf, strlen(buf));
60 goto retry; /* почему бы нет? */
61 } else if (ret == 0) {
62 strcpy(buf, "\tpid ");
63 strcat(buf, format_num(si->si_pid));
64 strcat(buf, " changed status\n");
65 write(1, buf, strlen(buf));
66 manage(si); /* обработать то, что произошло */
67 } else if (ret == -1 && errno == EINTR) {
68 write(1, "\tretrying\n", 10);
Поделиться:
Популярные книги
Кровь Василиска
1. Кровь Василиска
Фантастика:
фэнтези
попаданцы
аниме
4.25
рейтинг книги
Венецианский купец
1. Венецианский купец
Фантастика:
фэнтези
героическая фантастика
альтернативная история
7.31
рейтинг книги
Сопряжение 9
9. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
технофэнтези
рпг
5.00
рейтинг книги
На три фронта
3. Иной
Фантастика:
фэнтези
рпг
5.00
рейтинг книги
Авиатор: назад в СССР 11
11. Покоряя небо
Фантастика:
альтернативная история
5.00
рейтинг книги
Санек
1. Санек
Фантастика:
попаданцы
альтернативная история
4.00
рейтинг книги
Лорд Системы 8
8. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Мерзавец
3. Братья Майоровы
Любовные романы:
современные любовные романы
эро литература
короткие любовные романы
5.00
рейтинг книги
Игра топа. Между двух огней
2. Игра топа
Фантастика:
фэнтези
7.57
рейтинг книги
Провинциал. Книга 2
2. Провинциал
Фантастика:
космическая фантастика
рпг
аниме
5.00
рейтинг книги
Идущий в тени 6
6. Идущий в тени
Фантастика:
фэнтези
рпг
5.57
рейтинг книги
На границе империй. Том 9. Часть 4
17. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Крестоносец
7. Помещик
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Идеальный мир для Лекаря 10
10. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00