Читаем Linux API. Исчерпывающее руководство полностью

Жизненные циклы родительского и дочернего процессов обычно не совпадают — один из них живет дольше, чем другой. Из этого вытекает два вопроса.

• Кто становится родителем «осиротевшего» потомка? Ответ: init — предок всех процессов, имеющий идентификатор 1. Иными словами, после того, как родитель потомка завершит работу, вызов getppid() начнет возвращать 1. С помощью этого вызова можно узнать, жив ли еще настоящий родитель потомка (подразумевается, что потомок был создан любым другим процессом, кроме init).

Применение операции PR_SET_PDEATHSIG системного вызова prctl() (доступного только в Linux) позволяет сделать так, чтобы в случае потери родителя процесс получал выбранный сигнал.

• Что происходит с потомком, который завершается до того, как его родитель имел возможность выполнить wait()? Дело в том, что, хоть потомок и закончил свою работу, родителю все равно должно быть позволено сделать вызов wait(), чтобы определить причину завершения. Ядро решает эту проблему путем превращения потомка в «зомби». Это означает, что большинство ресурсов, занимаемых потомком, возвращаются системе и могут быть задействованы другими процессами. Единственная часть дочернего процесса, которая остается нетронутой, — это запись в таблице процессов ядра, хранящая (помимо прочего) идентификатор потомка, код завершения и статистику использования ресурсов (см. раздел 36.1).

Что касается «зомби», системы Unix следуют канонам, принятым в художественных фильмах, — процесс-«зомби» нельзя убить сигналом, даже если это SIGKILL (своеобразная серебряная пуля). Благодаря этому родитель всегда может выполнить вызов wait().

Когда родитель наконец делает вызов wait(), ядро удаляет процесс-«зомби», поскольку информация о нем больше не требуется. С другой стороны, если родитель завершает работу, так и не выполнив вызов wait(), процесс init удочеряет потомка и автоматически делает этот вызов самостоятельно, удаляя таким образом «зомби» из системы.

Если родитель создает потомка, но не успевает вызвать wait(), запись о дочернем процессе-«зомби» все равно продолжит храниться в таблице процессов ядра. Если будет создано слишком большое количество «зомби», они в какой-то момент переполнят эту таблицу, мешая созданию новых процессов. Поскольку «зомби» нельзя убить по сигналу, единственный способ удалить их из системы заключается в принудительном (или штатном) завершении работы их родителя; в этом случае они удочеряются процессом init, который начинает их ожидать, что приводит к их удалению из системы.

Последствия такой семантики имеют большое значение при проектировании долгоживущих родительских процессов, таких как сетевые серверы и командные оболочки, создающих большое количество потомков. Иначе говоря, родительский процесс в таких приложениях должен выполнять вызовы wait(), чтобы гарантировать удаление отработанных потомков из системы и не дать им превратиться в неубиваемых «зомби». Такие вызовы можно делать синхронно или асинхронно в ответ на сигнал SIGCHLD, как описывается в разделе 26.3.1.

В листинге 26.4 показан процесс создания «зомби» и тот факт, что их нельзя принудительно завершить с помощью сигнала SIGKILL. При запуске этой программы мы увидим следующий вывод:

$ ./make_zombie

Parent PID=1013

Child (PID=1014) exiting

1013 pts/4 00:00:00 make_zombie Вывод команды ps(1)

1014 pts/4 00:00:00 make_zombie

After sending SIGKILL to make_zombie (PID=1014):

1013 pts/4 00:00:00 make_zombie Вывод команды ps(1)

1014 pts/4 00:00:00 make_zombie

В выводе, представленном выше, видно, что команда ps(1) выводит строку , обозначающую процесс-«зомби».

Программа из листинга 26.4 использует функцию system() для выполнения консольной команды, передаваемой ей в виде символьно-строкового аргумента. Подробно эта функция описывается в разделе 27.6.


Листинг 26.4. Создание дочерних процессов-«зомби»

procexec/make_zombie.c

#include

#include  /* Для объявления basename() */

#include "tlpi_hdr.h"


#define CMD_SIZE 200


int

main(int argc, char *argv[])

{

char cmd[CMD_SIZE];

pid_t childPid;


setbuf(stdout, NULL); /* Отключаем буферизацию стандартного вывода */


printf("Parent PID=%ld\n", (long) getpid());


switch (childPid = fork()) {

case –1:

errExit("fork");


case 0: /* Потомок немедленно завершается, чтобы стать «зомби» */

printf("Child (PID=%ld) exiting\n", (long) getpid());

_exit(EXIT_SUCCESS);


default: /* Родитель */

sleep(3); /* Даем потомку шанс начать выполнение и завершиться */

snprintf(cmd, CMD_SIZE, "ps | grep %s", basename(argv[0]));

system(cmd); /* Видим потомка-«зомби» */


/* Теперь отправляем «зомби» сигнал о безусловном завершении */


if (kill(childPid, SIGKILL) == –1)

errMsg("kill");


sleep(3); /* Даем потомку шанс отреагировать на сигнал */

printf("After sending SIGKILL to zombie (PID=%ld):\n",

(long) childPid);

system(cmd); /* Опять видим потомка-«зомби» */


exit(EXIT_SUCCESS);

}

}

procexec/make_zombie.c


Перейти на страницу:

Похожие книги

C++ Primer Plus
C++ Primer Plus

C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible and easy-to-use self-study guide, this book is appropriate for both serious students of programming as well as developers already proficient in other languages.The sixth edition of C++ Primer Plus has been updated and expanded to cover the latest developments in C++, including a detailed look at the new C++11 standard.Author and educator Stephen Prata has created an introduction to C++ that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C++ language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.Review questions and programming exercises at the end of each chapter help readers zero in on the most critical information and digest the most difficult concepts.In C++ Primer Plus, you'll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:• A new detailed chapter on the changes and additional capabilities introduced in the C++11 standard• Complete, integrated discussion of both basic C language and additional C++ features• Clear guidance about when and why to use a feature• Hands-on learning with concise and simple examples that develop your understanding a concept or two at a time• Hundreds of practical sample programs• Review questions and programming exercises at the end of each chapter to test your understanding• Coverage of generic C++ gives you the greatest possible flexibility• Teaches the ISO standard, including discussions of templates, the Standard Template Library, the string class, exceptions, RTTI, and namespaces

Стивен Прата

Программирование, программы, базы данных
1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
C# 4.0: полное руководство
C# 4.0: полное руководство

В этом полном руководстве по C# 4.0 - языку программирования, разработанному специально для среды .NET, - детально рассмотрены все основные средства языка: типы данных, операторы, управляющие операторы, классы, интерфейсы, методы, делегаты, индексаторы, события, указатели, обобщения, коллекции, основные библиотеки классов, средства многопоточного программирования и директивы препроцессора. Подробно описаны новые возможности C#, в том числе PLINQ, библиотека TPL, динамический тип данных, а также именованные и необязательные аргументы. Это справочное пособие снабжено массой полезных советов авторитетного автора и сотнями примеров программ с комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки. Книга рассчитана на широкий круг читателей, интересующихся программированием на C#.Введите сюда краткую аннотацию

Герберт Шилдт

Программирование, программы, базы данных