Рейтинговые книги
Читем онлайн Linux программирование в примерах - Роббинс Арнольд

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 122 123 124 125 126 127 128 129 130 ... 253

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

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

$ <b>echo hi there | sed s/hi/hello/g</b>

hello there

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

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

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

3

4  #include &lt;stdio.h&gt;

5  #include &lt;errno.h&gt;

6  #include &lt;sys/types.h&gt;

7  #include &lt;sys/wait.h&gt;

8  #include &lt;unistd.h&gt;

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

22  if (pipe(pipefd) &lt; 0) { /* создать канал в самом начале */

23   perror(&quot;pipe&quot;);

24   exit(1);

25  }

26

27  if ((left_pid = fork()) &lt; 0) { /* порождение левого потомка */

28   perror(&quot;fork&quot;);

29   exit(1);

30  } else if (left_pid == 0)

31  left_child();

32

33  if ((right_pid = fork()) &lt; 0) { /* порождение правого потомка */

34   perror(&quot;fork&quot;);

35   exit(1);

36  } else if (right_pid == 0)

37  right_child();

38

39  close(pipefd[0])); /* закрыть родительские копии канала */

40  close(pipefd[1]);

41

42  while ((ret = wait(&amp;status)) &gt; 0) { /* wait for children */

43   if (ret == left_pid)

44    printf(&quot;left child terminated, status: %xn&quot;, status);

45   else if (ret == right_pid)

46    printf(&quot;right child terminated, status: %xn&quot;, status);

47   else

48    printf(&quot;yow! unknown child %d terminated, status %xn&quot;,

49     ret, status);

50  }

51

52  return 0;

53 }

Строки 22–25 создают канал. Это должно быть сделано в самом начале.

Строки 27–31 создают левого потомка, а строки 33–37 создают правого потомка. В обоих случаях родитель продолжает линейное исполнение ветви main() до тех пор, пока порожденный процесс не вызовет соответствующую функцию для манипулирования дескрипторами файла и осуществления exec.

Строки 39–40 закрывают родительскую копию канала.

Строки 42–50 в цикле ожидают потомков, пока wait() не вернет ошибку.

55 /* left_child --- осуществляет работу левого потомка */

56

57 void left_child(void)

58 {

59  static char *left_argv[] = { &quot;echo&quot;, &quot;hi&quot;, &quot;there&quot;, NULL };

60

61  close(pipefd[0]);

62  close(1);

63  dup(pipefd[1]);

64  close(pipefd[1]);

65

66  execvp(&quot;echo&quot;, left_argv);

67  _exit(errno == ENOENT ? 127 : 126);

68 }

69

70 /* right_child --- осуществляет работу правого потомка */

71

72 void right_child(void)

73 {

74  static char *right_argv[] = { &quot;sed&quot;, &quot;s/hi/hello/g&quot;, NULL };

75

76  close(pipefd[1]);

77  close(0);

78  dup(pipefd[0]);

79  close(pipefd[0]));

80

81  execvp(&quot;sed&quot;, right_argv);

82  _exit(errno == ENOENT ? 127 : 126);

83 }

Строки 57–68 являются кодом для левого потомка. Процедура следует приведенным выше шагам, закрывая ненужный конец канала, закрывая первоначальный стандартный вывод, помещая с помощью dup() записываемый конец канала на номер 1 и закрывая затем первоначальный записываемый конец. В этот момент строка 66 вызывает execvp(), и если она завершается неудачей, строка 67 вызывает _exit(). (Помните, что строка 67 никогда не выполняется, если execvp() завершается удачно.)

1 ... 122 123 124 125 126 127 128 129 130 ... 253
На этой странице вы можете бесплатно читать книгу Linux программирование в примерах - Роббинс Арнольд бесплатно.
Похожие на Linux программирование в примерах - Роббинс Арнольд книги

Оставить комментарий