На этом рисунке процесс выполнил 'dup2(1, 3)
В разделе 4.4.2 «Открытие и закрытие файлов» мы упомянули, что open()
creat()
) open()
и creat()
. (dup2()
является исключением, поскольку он предусматривает способ получения конкретного нового дескриптора файла, даже если он не является наименьшим неиспользуемым дескриптором.)При наличии правила «возвращения наименьшего неиспользуемого номера» в сочетании с функцией dup()
1. Создать канал с помощью pipe()
2. Создать то, что мы называем «левым потомком». Это процесс, стандартный вывод которого идет в канал. В данном процессе сделать следующее:
a. Использовать 'close(pipefd[0])
b. Использовать 'close(1)
c. Использовать 'dup(pipefd[1])
d. Использовать 'close(pipefd[1])
e. Выполнить exec
3. Создать то, что мы называем «правым потомком». Это процесс, стандартный ввод которого поступает из канала. Шаги для этого потомка являются зеркальным отражением шагов для левого потомка:
a. Использовать 'close(pipefd[1])
b. Использовать 'close(0)
c. Использовать 'dup(pipefd[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