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

Другой удобный прием — отображение в памяти файла /dev/zero (описывается в разделе 6.5.2, "/dev/zero"). Этот файл ведет себя так, как будто содержит бесконечное число нулевых байтов. Операции записи в него игнорируются. Описываемый прием часто применяется в пользовательских функциях выделения памяти, которым необходимо инициализировать блоки памяти.

<p>5.4. Каналы</p>

Канал — это коммуникационное устройство, допускающее однонаправленное взаимодействие. Данные, записываемые на "входном" конце канала, читаются на "выходном" его конце. Каналы являются последовательными устройствами: данные всегда читаются в том порядке, в котором они были записаны. Канал обычно используется как средство связи между двумя потоками одного процесса или между родительским и дочерним процессами.

В интерпретаторе команд канал создается оператором |. Например, показанная ниже команда заставляет интерпретатор запустить два дочерних процесса, один — для программы ls, а второй — для программы less:

% ls | less

Интерпретатор также формирует канал, соединяющий стандартный выходной поток подпроцесса ls со стандартным входным потоком подпроцесса less. Таким образом, имена файлов, перечисляемые программой ls, посылаются программе постраничной разбивки less в том порядке, в котором они отображались бы нетерминале.

Информационная емкость канала ограничена. Если пишущий процесс помещает данные в канал быстрее, чем читающий процесс их извлекает, и буфер канала переполняется, то пишущий процесс блокируется до тех пор, пока буфер не освободится. И наоборот: если читающий процесс обращается к каналу, в который еще не успели поступить данные, он блокируется в ожидании данных. Таким образом, канал автоматически синхронизирует оба процесса.

<p>5.4.1. Создание каналов</p>

Канал создается с помощью функции pipe(). Ей необходимо передать массив из двух целых чисел. В элементе с индексом 0 функция сохраняет дескриптор файла, соответствующего выходному концу канала, а в элементе с индексом 1 сохраняется дескриптор файла, соответствующего входному концу канала. Рассмотрим следующий фрагмент программы

int pipe_fds[2];

int read_fd;

int write_fd;

pipe(pipe_fds);

read_fd = pipe_fds[0];

write_fd = pipe_fds[1];

Данные, записываемые в файл write_fd, могут быть прочитаны из файла read_fd.

<p>5.4.2. Взаимодействие родительского и дочернего процессов</p>

Функция pipe() создает два файловых дескриптора, которые действительны только в текущем процессе и его потомках. Эти дескрипторы нельзя передать постороннему процессу. Дочерний процесс получает копии дескрипторов после завершения функции fork().

В программе, показанной в листинге 5.7. родительский процесс записывает в канал строку, а дочерний процесс читает ее. С помощью функции fdopen() файловые дескрипторы приводятся к типу FILE*. Благодаря этому появляется возможность использовать высокоуровневые функции ввода-вывода, такие как printf() и fgets().

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

#include

#include

#include

/* Запись указанного числа копий (COUNT) сообщения (MESSAGE)

   в поток (STREAM) с паузой между каждой операцией. */

void writer(const char* message, int count, FILE* stream) {

 for (; count > 0; --count) {

 /* Запись сообщения в поток с немедленным "выталкиванием"

    из буфера. */

 fprintf(stream, "%s\n", message);

 fflush(stream);

 /* Небольшая пауза. */

 sleep(1);

}

/* Чтение строк из потока, пока он не опустеет. */

void reader(FILE* stream) {

 char buffer[1024];

 /* Чтение данных, пока не будет обнаружен конец потока.

    Функция fgets() завершается, когда встречает символ

    новой строки или признак конца файла. */

 while (!feof(stream)

  && !ferror(stream)

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

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