Вызов функции fork

Вызов функции fork может привести к получению трех возможных результатов: отрицательного значения, которое свидетельствует о том, что возникла ошибка (например, в системе нет достаточного объема памяти для создания нового процесса), положительного значения, по которому можно судить о том, что вызов функции был выполнен успешно и текущий процесс является родительским, и нулевое значение, свидетельствующее о том, что вызов выполнен успешно и текущий процесс является вновь созданным дочерним процессом.

В рассматриваемом примере кода в случае возникновения ошибки сервер выводит сообщение в стандартный поток вывода сообщений об ошибках и вызывает функцию exit, чтобы завершить свою работу с кодом завершения 1. В соответствии с общепринятым соглашением, ненулевой код завершения указывает на аварийное окончание процесса.

В случае успешного выполнения функции fork в операторе if возвращаемое значение используется для проведения различия между родительским и дочерним процессами. Первоначальный родительский процесс нормально завершает свою работу, а дочерний процесс продолжает выполнение и становится сервером. Проще всего можно наглядно представить себе этот процесс с точки зрения пользователя. Предположим, что приведенный выше код выполняется в некоторой серверной программе Q. Для запуска сервера пользователь вводит в качестве команды имя файла с программой сервера. После ввода этой команды у пользователя создается впечатление, что она выполняется почти мгновенно, и он сразу же получает приглашение к вводу следующей команды. Но если пользователь запросит список процессов, он увидит, что сервер создал свою же копию и что эта копия продолжает выполняться в фоновом режиме.

В приведенном выше коде есть еще одна небольшая тонкость: он позволяет полностью отделить демон от его родительского процесса. В любой момент времени каждый процесс UNIX имеет родительский процесс, и в действиях, выполняемых некоторыми системными функциями UNIX, учитываются родительско-дочерние связи. После вызова функции fork завершается родительский процесс сервера, в результате чего вновь созданный дочерний процесс какое-то время находится вне родительско-дочерней связи. В операционной системе UNIX предусмотрено, что если любой процесс лишается связи с родительским процессом, для него родительским процессом должен стать начальный процесс системы (init). Для обозначения такого действия принято говорить, что дочерний процесс, лишенный связи с родительским, был унаследован процессом init2. Хотя сам факт такого наследования может показаться незначительным, описанное действие является очень важным, поскольку оно означает, что завершение работы сервера может быть выполнено корректно, так как процесс init вызывает функцию wait операционной системы Linux для завершения работы каждого из своих дочерних процессов.

30.4. Открытые дескрипторы и наследование дескрипторов

Любой дочерний процесс Linux наследует копии дескрипторов файлов или сокетов, открытых родительским процессом к моменту создания этого дочернего процесса. Поэтому набор дескрипторов, наследуемых серверным процессом, зависит от того, как был запущен этот процесс.

Поскольку в системе Linux для работы с файлами и другими объектами применяется механизм подсчета ссылок, то сохранение в программе открытых дескрипторов может привести к непроизводительному расходованию ресурсов. Например, предположим, что родительский процесс открыл файл, а затем вызвал на выполнение сервер, который выполнил ветвление и перешел в фоновый режим. Даже если родительский процесс закрыл свою копию дескриптора файла, в сервере все еще остается открытой другая копия, и поэтому файл не будет закрыт. В результате файл не может быть удален с диска до тех пор, пока сервер не завершит свою работу.

Сервер должен закрыть все унаследованные им дескрипторы файлов, чтобы исключить непроизводительное потребление ресурсов.

Похожие статьи Меню Опрос Фото Популярное