- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
50
51 writed, entered, strlen(entered));
52 for (i =0; i < nkids; i++) {
53 if (kids[i] == NOT_USED)
54 continue;
55
56 retry:
57 if ((ret = waitpid(kids[i], &status, WNOHANG)) == kids[i]) {
58 strcpy(buf, "treaped process ");
59 strcat(buf, format_num(ret));
60 strcat(buf, "n");
61 write(1, buf, strlen(buf));
62 kids[i] = NOT_USED;
63 } else if (ret == 0) {
64 strcpy(buf, "tpid ");
65 strcat(buf, format_num(kids[i]));
66 strcat(buf, " not available yetn");
67 write(1, buf, strlen(buf));
68 } else if (ret == -1 && errno == EINTR) {
69 write(1, "tretryingn", 10);
70 goto retry;
71 } else {
72 strcpy(buf, "twaitpid() failed: ");
73 strcat(buf, strerror(errno));
74 strcat(buf, "n");
75 write(1, buf, strlen(buf));
76 }
77 }
78 write(1, exited, strlen(exited));
79 }
Строки 51 и 58 выводят «входное» и «завершающее» сообщения, так что мы можем ясно видеть, когда вызывается обработчик сигнала. Другие сообщения начинаются с ведущего символа TAB.
Главной частью обработчика сигнала является большой цикл, строки 52–77. Строки 53–54 проверяют на NOT_USED и продолжают цикл, если текущий слот не используется.
Строка 57 вызывает waitpid() с PID текущего элемента kids. Мы предусмотрели опцию WNOHANG, которая заставляет waitpid() возвращаться немедленно, если затребованный потомок недоступен. Этот вызов необходим, так как возможно, что не все потомки завершились.
Основываясь на возвращенном значении, код предпринимает соответствующее действие. Строки 57–62 обрабатывают случай обнаружения потомка, выводя сообщение и помещая в соответствующий слот в kids значение NOT_USED.
Строки 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 signaln");
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, один сигнал на потомка */
2
/* ...не изменившийся код пропущен... */
12
13 pid_t kids[MAX_KIDS];
14 size_t nkids = 0;
15 size_t kidsleft = 0; /* <<< Добавлено */
16
/* ...не изменившийся код пропущен... */
41
42 /* childhandler --- перехват SIGCHLD, опрос всех доступных потомков */
43
44 void childhandler(int sig)
45 {
46 int status, ret;
47 int i;
48 char buf[100];
49 static const char entered[] = "Entered childhandlern";
50 static const char exited[] = "Exited childhandlern";
51
52 write(1, entered, strlen(entered));
53 for (i = 0; i < nkids; i++) {
54 if (kids[i] == NOT_USED)
55 continue;
56
57 retry:
58 if ((ret = waitpid(kids[i], &status, WNOHANG)) == kids[i]) {
59 strcpy(buf, "treaped process ");
60 strcat(buf, format_num(ret));
61 strcat(buf, "n");
62 write(1, buf, strlen(buf));
63 kids[i] = NOT_USED;
64 kidsleft--; /* <<< Добавлено */
65 } else if (ret == 0) {
/* ...не изменившийся код пропущен... */
80 write(1, exited, strlen(exited));
81 }
Это идентично предыдущей версии за тем исключением, что у нас есть новая переменная, kidsleft, указывающая, сколько имеется не опрошенных потомков. Строки 15 и 64 помечают новый код.
83 /* main --- установка относящейся к порожденным процессам сведений
и сигналов, создание порожденных процессов */
84
85 int main(int argc, char **argv)
86 {
/* ...не изменившийся код пропущен... */
100
101 sigemptyset(&childset);
102 sigaddset(&childset, SIGCHLD);
103
104 /* sigprocmask(SIG_SETMASK, &childset, NULL); /* блокирование в коде main */
105
106 for (nkids = 0; nkids < 5; nkids++) {
107 if ((kids[nkids] = fork()) == 0) {
108 sleep(3);
109 _exit(0);
110 }
111 kidsleft++; /* <<< Added */
112 }
113
114 /* sleep(5); /* дать потомкам шанс завершиться */
115
116 while (kidsleft > 0) { /* <<< Добавлено */
117 printf("waiting for signalsn");
118 sigsuspend(&emptyset);
119 } /* <<< Добавлено */
120
121 return 0;
122 }
Здесь код также почти идентичен. Строки 104 и 114 закомментированы из предыдущей версии, а строки 111, 116 и 119 добавлены. Удивительно, при запуске поведение меняется в зависимости от версии ядра!
$ uname -a /* Отобразить версию системы */
Linux example1 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686 i386 GNU/Linux
$ ch10-reap2 /* Запустить программу */
waiting for signals
Entered childhandler /* Опрос одного потомка */
reaped process 2702
pid 2703 not available yet
pid 2704 not available yet
pid 2705 not available yet
pid 27 06 not available yet
Exited childhandler
waiting for signals
Entered childhandler /* И следующего */
reaped process 2703
pid 2704 not available yet
pid 2705 not available yet
pid 2706 not available yet
Exited childhandler

