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

Ранние реализации BSD входили в число операционных систем, в которых вызов fork() выполнял полноценное дублирование данных, кучи и стека родителя. Как уже было замечено выше, это довольно расточительно, особенно если за вызовом fork() следует функция exec(). В связи с этим в более поздних версиях BSD-систем появился системный вызов vfork(), который отличается гораздо большей эффективностью, хотя и имеет немного другую (на самом деле довольно странную) семантику. В современных системах UNIX вызов fork() выполняет копирование при записи, что значительно более экономно по сравнению со старыми реализациями; благодаря этому необходимость в функции vfork() во многом отпала. Тем не менее в случае, если вам нужна самая быстрая операция создания дочерних процессов, операционная система Linux (как и многие другие реализации UNIX) тоже поддерживает вызов vfork() с семантикой, принятой в BSD-системах. Но, поскольку эта необычная семантика может привести к неочевидным программным ошибкам, vfork() рекомендуется избегать; исключение составляют те редкие случаи, когда он обеспечивает существенный прирост производительности.

Как и fork(), вызов vfork() применяется вызывающим процессом для создания нового потомка. Однако он специально был спроектирован так, чтобы его можно было использовать в программах, в которых дочерний процесс сразу же делает вызов exec().

#include


pid_t vfork(void);

В родителе: возвращает идентификатор потомка при успешном завершении или –1 при ошибке; в успешно созданном потомке всегда возвращает 0

Функция vfork() имеет два отличия от системного вызова fork(), которые делают ее более эффективной.

• Страницы виртуальной памяти или таблицы страниц не дублируются для дочернего процесса. Вместо этого потомок и родитель делят память до тех пор, пока один из них не выполнит успешный вызов exec() или _exit(), чтобы завершить работу.

• Выполнение родительского процесса приостанавливается до тех пор, пока потомок не вызовет exec() или _exit().

Эти два свойства имеют важные последствия. Поскольку потомок использует память родителя, любые изменения, вносимые им в сегменты данных, кучи или стека, будут доступны самому родительскому процессу, как только он возобновит работу. Более того, выполнение потомком функции между вызовами vfork() и exec() (или _exit()) тоже коснется родителя. Это похоже на пример, описанный в разделе 6.8, когда вызов longjmp() выполняет переход внутрь функции, которая уже вернула управление (завершилась). Чаще всего это приводит к ошибке сегментации (SIGSEGV).

Есть несколько вещей, которые потомок может делать между вызовами vfork() и exec(), не затрагивая при этом своего родителя. К таковым относится операция открытия дескриптора файла (не путать с потоками stdio (библиотеки)). Поскольку таблица файловых дескрипторов каждого процесса хранится в пространстве ядра (см. раздел 5.4) и дублируется во время вызова vfork(), родитель не будет знать об операциях с дескрипторами файлов, выполняемых потомком.

SUSv3 гласит, что поведение программы является неопределенным, если она: а) изменяет любые данные, кроме переменной типа pid_t, применяемой для хранения значения, возвращаемого вызовом vfork(); б) возвращается из функции, в которой произошел вызов vfork(); в) вызывает любую другую функцию до успешного выполнения _exit() или exec().

При рассмотрении системного вызова clone() в разделе 28.2 мы увидим, что потомок, созданный с помощью функций fork() или vfork(), получает собственные копии некоторых других атрибутов процесса.

Семантика функции vfork() указывает на то, что после ее вызова потомок гарантированно получит ресурсы центрального процессора раньше родителя. В разделе 24.2 отмечалось, что вызов fork() не дает такой гарантии, поэтому после него выполнение может перейти как к родительскому, так и к дочернему процессу.

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

$ ./t_vfork

Child executing Хотя потомок приостановился, родитель не продолжил работу

Parent executing

istack=666

Последняя строчка вывода показывает изменение, внесенное потомком в переменную istack, которая принадлежит родителю.


Листинг 24.4. Использование вызова vfork()

procexec/t_vfork.c

#include "tlpi_hdr.h"


int

main(int argc, char *argv[])

{

int istack = 222;


switch (vfork()) {

case –1:

errExit("vfork");


case 0: /* Первым выполняется потомок (в пространстве памяти родителя) */

sleep(3); /* Даже если процесс остановится на некоторое время,

родитель все равно не продолжит работу */

write(STDOUT_FILENO, "Child executing\n", 16);

istack *= 3; /* Это изменение будет доступно родителю */

_exit(EXIT_SUCCESS);


default: /* Родитель блокируется, пока существует его потомок */

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

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

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#.Введите сюда краткую аннотацию

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

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