Обработка зомбированных процессов
Обработка зомбированных процессов
Очевидно, что нам не хотелось бы оставлять процессы в виде зомби. Они занимают место в ядре, и в конце концов у нас может не остаться идентификаторов для нормальных процессов. Когда мы выполняем функцию fork для дочерних процессов, необходимо с помощью функции wait дождаться их завершения, чтобы они не превратились в зомби. Для этого мы устанавливаем обработчик сигналов для перехватывания сигнала SIGCHLD и внутри обработчика вызываем функцию wait. (Функции wait и waitpid мы опишем в разделе 5.10.) Обработчик сигналов мы устанавливаем с помощью вызова функции
Signal(SIGCHLD, sig_chld);
в листинге 5.1, после вызова функции listen. (Необходимо сделать это до вызова функции fork для первого дочернего процесса, причем только один раз.) Затем мы определяем обработчик сигнала — функцию sig_chld, представленную в листинге 5.6.
Листинг 5.6. Версия обработчика сигнала SIGCHLD, вызывающая функцию wait (усовершенствованная версия находится в листинге 5.8)
//tcpcliserv/sigchldwait.с
1 #include "unp.h"
2 void
3 sig_chld(int signo)
4 {
5 pid_t pid;
6 int stat;
7 pid = wait(&stat);
8 printf("child terrmnated ", pid);
9 return;
10 }
ВНИМАНИЕ
В обработчике сигналов не рекомендуется вызов стандартных функций ввода-вывода, таких как printf, по причинам, изложенным в разделе 11.18. В данном случае мы вызываем функцию printf как средство диагностики, чтобы увидеть, когда завершается дочерний процесс.
В системах System V и Unix 98 дочерний процесс не становится зомби, если процесс задает действие SIG_IGN для SIGCHLD. К сожалению, это верно только для System V и Unix 98. В POSIX прямо сказано, что такое поведение этим стандартом не предусмотрено. Переносимый способ обработки зомби состоит в том, чтобы перехватывать сигнал SIGCHLD и вызывать функцию wait или waitpid.
Если мы откомпилируем в Solaris 9 программу, представленную в листинге 5.1, вызывая функцию Signal с нашим обработчиком sig_chld, и будем использовать функцию signal из системной библиотеки (вместо нашей версии, показанной в листинге 5.5), то получим следующее:
solaris % tcpserv02 & запускаем сервер в фоновом режиме
[2] 16939
solaris % tcpcli01 127.0.0.1 затем клиент
hi there набираем эту строку
hi there и она отражается сервером
^D вводим символ конца файла
child 16942 terminated функция printf из обработчика сигнала выводит эту строку
accept error: Interrupted system call но функция main преждевременно прекращает выполнение
Последовательность шагов в этом примере такова:
1. Мы завершаем работу клиента, вводя символ EOF. TCP клиента посылает сегмент FIN серверу, и сервер отвечает сегментом ACK.
2. Получение сегмента FIN доставляет EOF ожидающей функции readline дочернего процесса. Дочерний процесс завершается.
3. Родительский процесс блокирован в вызове функции accept, когда доставляется сигнал SIGCHLD. Функция sig_chld (наш обработчик сигнала) выполняется, функция wait получает PID дочернего процесса и статус завершения, после чего из обработчика сигнала вызывается функция printf. Обработчик сигнала возвращает управление.
4. Поскольку сигнал был перехвачен родительским процессом, в то время как родительский процесс был блокирован в медленном (см. ниже) системном вызове (функция accept), ядро заставляет функцию accept возвратить ошибку EINTR (прерванный системный вызов). Родительский процесс не обрабатывает эту ошибку корректно (см. листинг 5.1), поэтому функция main преждевременно завершается.
Цель данного примера — показать, что при написании сетевых программ, перехватывающих сигналы, необходимо получать информацию о прерванных системных вызовах и обрабатывать их. В этом специфичном для Solaris 2.5 примере функция signal из стандартной библиотеки С не осуществляет автоматический перезапуск прерванного вызова, то есть флаг SA_RESTART, установленный нами в листинге 5.5, не устанавливается функцией signal из системной библиотеки. Некоторые другие системы автоматически перезапускают прерванный системный вызов. Если мы запустим тот же пример в 4.4BSD, используя ее библиотечную версию функции signal, ядро перезапустит прерванный системный вызов и функция accept не возвратит ошибки. Одна из причин, по которой мы определяем нашу собственную версию функции signal и используем ее далее, — решение этой потенциальной проблемы, возникающей в различных операционных системах (см. листинг 5.5).
Кроме того, мы всегда программируем явную функцию return для наших обработчиков сигналов (см. листинг 5.6), даже если функция ничего не возвращает (void), чтобы этот оператор напоминал нам о возможности прерывания системного вызова при возврате из обработчика.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Идентификаторы процессов
Идентификаторы процессов Процесс может получить идентификатор и дескриптор нового дочернего процесса из структуры PROCESS_INFORMATION. Разумеется, закрытие дескриптора дочернего процесса не приводит к уничтожению самого процесса; становится невозможным лишь доступ к нему со
10.2 Атрибуты процессов
10.2 Атрибуты процессов 10.2.1. Идентификатор процесса и происхождение Два из наиболее фундаментальных атрибутов — это идентификатор процесса (process ID), или pid, а также идентификатор его родительского процесса. Идентификатор pid — это положительное целое число, которое
10.4. Примитивы процессов
10.4. Примитивы процессов Несмотря на относительно длинную дискуссию, необходимую для описания процесса, создание и уничтожение процессов в Linux достаточно
10.6.3. Группы процессов
10.6.3. Группы процессов Одной из главных целей Unix было создание набора простых инструментов, которые могут быть использованы вместе сложными способами (с помощью механизмов, подобных программным каналам). Большинство пользователей Linux делали нечто вроде следующего
Модель процессов ILE
Модель процессов ILE Модель процессов ILE впервые появилась на AS/400 в версии V2R3 вместе с одноименной программной моделью и компиляторами. Исходная модель процессов и модель процессов ILE сосуществовали в AS/400 до перехода на RISC-процессоры. Затем исходные модели были
Структура процессов ILE
Структура процессов ILE Сначала разберемся с компонентами процесса ILE и сокращениями, их обозначающими:Блок управления процессом PCB (Process Control Block) содержится в системном объекте MI. Ранее мы говорили, что этот системный объект, кроме всего прочего, содержит TDE процесса.
Типы процессов
Типы процессов Системные процессы Системные процессы являются частью ядра и всегда расположены в оперативной памяти. Системные процессы не имеют соответствующих им программ в виде исполняемых файлов и запускаются особым образом при инициализации ядра системы.
9.1.2 Выгрузка процессов
9.1.2 Выгрузка процессов Ядро выгружает процесс, если испытывает потребность в свободной памяти, которая может возникнуть в следующих случаях:1. Произведено обращение к системной функции fork, которая должна выделить место в памяти для процесса-потомка.2. Произведено
3.3. Взаимодействие процессов
3.3. Взаимодействие процессов Из всех средств межпроцессного взаимодействия, которыми так богаты UNIX-подобные ОС, в этой главе мы рассмотрим только конвейеры и
Обработка событий во время продолжительных процессов
Обработка событий во время продолжительных процессов Когда мы вызываем QApplication::exec(), тем самым начинаем цикл обработки событий Qt. При запуске пpилoжeния Qt генерирует несколько событий для отображения на экране виджетов. После этого начинает выполняться цикл обработки
5.7. Диаграммы процессов.
5.7. Диаграммы процессов. Существенное: процессоры, устройства и соединения Диаграммы процессов используются, чтобы показать распределение процессов по процессорам в физическом проекте системы. Отдельная диаграмма процессов показывает один ракурс структуры процессов
7.2. Каталоги процессов
7.2. Каталоги процессов Файловая система /proc содержит по одному каталогу для каждого выполняющегося в данный момент процесса. Именем каталога является идентификатор процесса.[22] Каталоги появляются и исчезают динамически по мере запуска и завершения процессов. В каждом
Перечисление процессов
Перечисление процессов Для отображения списка процессов используется функция, код которой приведен в листинге 7.27.Листинг 7.27private void fillProcessList() { Cursor.Current = Cursors.WaitCursor; // Получаем список запущенных процессов processes = Process.GetProcesses(); // Заполняем ListView ListViewItem