Linux программирование в примерах - Роббинс Арнольд
Когда левый потомок завершает работу, он заканчивается. Система после этого закрывает все его дескрипторы файлов. Когда это случается, правый потомок получает в конечном счете уведомление конца файла и тоже может завершить работу и выйти.
Следующая программа,
ch09-pipeline.c$ <b>echo hi there | sed s/hi/hello/g</b>hello thereВот программа:
1 /* ch09-pipeline.c --- ответвляет два процесса в их собственный конвейер.2 Для краткости проверка ошибок сведена к минимуму. */34 #include <stdio.h>5 #include <errno.h>6 #include <sys/types.h>7 #include <sys/wait.h>8 #include <unistd.h>910 int pipefd[2];1112 extern void left_child(void), right_child(void);1314 /* main --- порождение процессов и ожидание их завершения */1516 int main(int argc, char **argv)17 {18 pid_t left_pid, right_pid;19 pid_t ret;20 int status;2122 if (pipe(pipefd) < 0) { /* создать канал в самом начале */23 perror("pipe");24 exit(1);25 }2627 if ((left_pid = fork()) < 0) { /* порождение левого потомка */28 perror("fork");29 exit(1);30 } else if (left_pid == 0)31 left_child();3233 if ((right_pid = fork()) < 0) { /* порождение правого потомка */34 perror("fork");35 exit(1);36 } else if (right_pid == 0)37 right_child();3839 close(pipefd[0])); /* закрыть родительские копии канала */40 close(pipefd[1]);4142 while ((ret = wait(&status)) > 0) { /* wait for children */43 if (ret == left_pid)44 printf("left child terminated, status: %xn", status);45 else if (ret == right_pid)46 printf("right child terminated, status: %xn", status);47 else48 printf("yow! unknown child %d terminated, status %xn",49 ret, status);50 }5152 return 0;53 }Строки 22–25 создают канал. Это должно быть сделано в самом начале.
Строки 27–31 создают левого потомка, а строки 33–37 создают правого потомка. В обоих случаях родитель продолжает линейное исполнение ветви
main()execСтроки 39–40 закрывают родительскую копию канала.
Строки 42–50 в цикле ожидают потомков, пока
wait()55 /* left_child --- осуществляет работу левого потомка */5657 void left_child(void)58 {59 static char *left_argv[] = { "echo", "hi", "there", NULL };6061 close(pipefd[0]);62 close(1);63 dup(pipefd[1]);64 close(pipefd[1]);6566 execvp("echo", left_argv);67 _exit(errno == ENOENT ? 127 : 126);68 }6970 /* right_child --- осуществляет работу правого потомка */7172 void right_child(void)73 {74 static char *right_argv[] = { "sed", "s/hi/hello/g", NULL };7576 close(pipefd[1]);77 close(0);78 dup(pipefd[0]);79 close(pipefd[0]));8081 execvp("sed", right_argv);82 _exit(errno == ENOENT ? 127 : 126);83 }Строки 57–68 являются кодом для левого потомка. Процедура следует приведенным выше шагам, закрывая ненужный конец канала, закрывая первоначальный стандартный вывод, помещая с помощью
dup()execvp()_exit()execvp()