Читаем Linux программирование в примерах полностью

На этом рисунке процесс выполнил 'dup2(1, 3)', чтобы сделать дескриптор файла 3-й копией стандартного вывода, дескриптора файла 1. Точно как описано ранее, эти два дескриптора разделяют общее смещение открытого файла.

В разделе 4.4.2 «Открытие и закрытие файлов» мы упомянули, что open()creat()) всегда возвращают наименьшее целое значение неиспользуемого дескриптора для открываемого файла. Этому правилу следуют почти все системные вызовы, которые возвращают новые дескрипторы файлов, а не только open() и creat(). (dup2() является исключением, поскольку он предусматривает способ получения конкретного нового дескриптора файла, даже если он не является наименьшим неиспользуемым дескриптором.)

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

1. Создать канал с помощью pipe(). Это должно быть сделано сначала, чтобы два порожденных процесса могли унаследовать дескрипторы открытых файлов.

2. Создать то, что мы называем «левым потомком». Это процесс, стандартный вывод которого идет в канал. В данном процессе сделать следующее:

 a. Использовать 'close(pipefd[0])', поскольку читаемый конец канала в левом потомке не нужен.

 b. Использовать 'close(1)', чтобы закрыть первоначальный стандартный вывод.

 c. Использовать 'dup(pipefd[1])' для копирования записываемого конца канала в дескриптор файла 1.

 d. Использовать 'close(pipefd[1])', поскольку нам не нужны две копии открытого дескриптора.

 e. Выполнить exec для запускаемой программы.

3. Создать то, что мы называем «правым потомком». Это процесс, стандартный ввод которого поступает из канала. Шаги для этого потомка являются зеркальным отражением шагов для левого потомка:

 a. Использовать 'close(pipefd[1])', поскольку записываемый конец канала в правом потомке не нужен.

 b. Использовать 'close(0)', чтобы закрыть первоначальный стандартный ввод.

 c. Использовать 'dup(pipefd[0])' для копирования читаемого конца канала в дескриптор файла 0.

 d. Использовать 'close(pipefd[0])', поскольку нам не нужны две копии открытого дескриптора.

 e. Выполнить exec для запускаемой программы.

4. В родителе закрыть оба конца канала — 'close(pipefd[0]); close(pipefd[1])'.

5. Наконец, использовать в родителе wait() для ожидания завершения обоих порожденных процессов.

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

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

Когда левый потомок завершает работу, он заканчивается. Система после этого закрывает все его дескрипторы файлов. Когда это случается, правый потомок получает в конечном счете уведомление конца файла и тоже может завершить работу и выйти.

Следующая программа, ch09-pipeline.c, создает эквивалент следующего конвейера оболочки:

$ echo hi there | sed s/hi/hello/g

hello there

Вот программа:

1  /* ch09-pipeline.c --- ответвляет два процесса в их собственный конвейер.

2     Для краткости проверка ошибок сведена к минимуму. */

3

4  #include

5  #include

6  #include

7  #include

8  #include

9

10 int pipefd[2];

11

12 extern void left_child(void), right_child(void);

13

14 /* main --- порождение процессов и ожидание их завершения */

15

16 int main(int argc, char **argv)

17 {

18  pid_t left_pid, right_pid;

19  pid_t ret;

20  int status;

21

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

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

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

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

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

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

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