Книга: Программирование для Linux. Профессиональный подход

Листинг 5.7. (pipe.c) Общение с дочерним процессом посредством канала

Листинг 5.7. (pipe.c) Общение с дочерним процессом посредством канала

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
/* Запись указанного числа копий (COUNT) сообщения (MESSAGE)
   в поток (STREAM) с паузой между каждой операцией. */
void writer(const char* message, int count, FILE* stream) {
 for (; count > 0; --count) {
 /* Запись сообщения в поток с немедленным "выталкиванием"
    из буфера. */
 fprintf(stream, "%sn", message);
 fflush(stream);
 /* Небольшая пауза. */
 sleep(1);
}
/* Чтение строк из потока, пока он не опустеет. */
void reader(FILE* stream) {
 char buffer[1024];
 /* Чтение данных, пока не будет обнаружен конец потока.
    Функция fgets() завершается, когда встречает символ
    новой строки или признак конца файла. */
 while (!feof(stream)
  && !ferror(stream)
  && fgets(buffer, sizeof (buffer), stream) != NULL)
  fputs(buffer, stdout);
}
int main() {
 int fds[2];
 pid_t pid;
 /* Создание канала. Дескрипторы обоих концов канала
    помещаются в массив FDS. */
 pipe(fds);
 /* порождение дочернего процесса. */
 pid = fork();
 if (pid == (pid_t)0) {
  FILE* stream;
  /* Это дочерний процесс. Закрываем копию входного конца
     канала. */
  close(fds[1]);
  /* Приводим дескриптор выходного конца канала к типу FILE*
     и читаем данные из канала. */
  stream = fdopen(fds[0], "r");
  reader(stream);
  close(fds[0]);
 } else {
  /* Это родительский процесс. */
  FILE* stream;
  /* Закрываем копию выходного конца канала. */
  close(fds[0]);
  /* Приводим дескриптор входного конца канала к типу FILE*
     и записываем данные в канал. */
  stream = fdopen(fds[1], "w");
  writer("Hello, world.", 5, stream);
  close(fds[1]);
 }
 return 0;
}

Сначала в программе объявляется массив fds, состоящий из двух целых чисел. Функция pipe() создает канал и помещает в массив дескрипторы входного и выходного концов канала. Затем функция fork() порождает дочерний процесс. После закрытия выходного конца канала родительский процесс начинает записывать строки в канал. Дочерний процесс читает строки из канала, предварительно закрыв его входной конец.

Обратите внимание на то. что в функции writer() родительский процесс принудительно "выталкивает" буфер канала, вызывая функцию fflush(). Без этого строка могла бы ""застрять" в буфере и отправиться в канал только после завершения родительского процесса.

При вызове команды ls | less функция fork() выполняется дважды: один раз — для дочернего процесса ls, второй раз — для дочернего процесса less. Оба процесса наследуют копии дескрипторов канала, поэтому могут общаться друг с другом. О соединении несвязанных процессов речь пойдет ниже, в разделе 5.4.5, "Каналы FIFO".

Оглавление книги

Похожие страницы

Генерация: 4.058. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз