Чтение онлайн

ЖАНРЫ

Основы программирования в Linux
Шрифт:
Открытие FIFO с помощью open

Основное ограничение при открытии канала FIFO состоит в том, что программа не может открыть FIFO для чтения и записи с режимом

O_RDWR
. Если программа нарушит это ограничение, результат будет непредсказуемым. Это очень разумное ограничение, т.к., обычно канал FIFO применяется для передачи данных в одном направлении, поэтому нет нужды в режиме
O_RDWR
. Процесс стал бы считывать обратно свой вывод, если бы канал был открыт для чтения/записи.

Если вы действительно хотите передавать данные между программами в обоих направлениях, гораздо

лучше использовать пару FIFO или неименованных каналов, по одному для каждого направления передачи, или (что нетипично) явно изменить направление потока данных, закрыв и снова открыв канал FIFO. Мы вернемся к двунаправленному обмену данными с помощью каналов FIFO чуть позже в этой главе.

Другое различие между открытием канала FIFO и обычного файла заключается в использовании флага

open_flag
(второй параметр функции
open
) со значением
O_NONBLOCK
. Применение этого режима
open
изменяет способ обработки не только вызова
open
, но и запросов
read
и
write
для возвращаемого файлового дескриптора.

Существует четыре допустимых комбинации значений

O_RDONLY
,
O_WRONLY
и
O_NONBLOCK
флага. Рассмотрим их все по очереди.

open(const char *path, O_RDONLY);

В этом случае вызов

open
блокируется, он не вернет управление программе до тех пор, пока процесс не откроет этот FIFO для записи. Это похоже на первый пример с командой
cat
.

open(const char *path, O_RDONLY | O_NONBLOCK);

Теперь вызов

open
завершится успешно и вернет управление сразу, даже если канал FIFO не был открыт для записи каким-либо процессом.

open(const char *path, O_WRONLY);

В данном случае вызов

open
будет заблокирован до тех пор, пока процесс не откроет тот же канал FIFO для чтения.

open(const char *path, O_WRONLY | O_NONBLOCK);

Этот вариант вызова всегда будет возвращать управление немедленно, но если ни один процесс не открыл этот канал FIFO для чтения,

open
вернет ошибку, -1, и FIFO не будет открыт. Если есть процесс, открывший FIFO для чтения, возвращенный файловый дескриптор может использоваться для записи в канал FIFO.

Примечание

Обратите внимание на асимметрию в использовании

O_NONBLOCK
с
O_RDONLY
и
O_WRONLY
, заключающуюся в том, что неблокирующий вызов
open
для записи завершается аварийно, если ни один процесс не открыл канал для чтения, а неблокирующий вызов
open
для чтения не возвращает ошибку. На поведение вызова
close
флаг
O_NONBLOCK
влияния не оказывает.

Выполните упражнение 13.11.

Упражнение 13.11. Открытие файлов FIFO

Теперь рассмотрим, как можно использовать поведение вызова

open
с флагом, содержащим
O_NONBLOCK
, для синхронизации двух процессов. Вместо применения нескольких программ-примеров вы напишите одну тестовую программу fifo2.c, которая позволит исследовать поведение каналов FIFO при передаче ей
разных параметров.

1. Начните с заголовочных файлов, директивы

#define
и проверки правильности количества предоставленных аргументов командной строки:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#define FIFO_NAME "/tmp/my_fifo"

int main(int argc, char *argv[]) {

 int res;

 int open_mode = 0;

 int i;

 if (argc < 2) {

fprintf(stderr, "Usage: %s <some combination of\

O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv);

exit(EXIT_FAILURE);

 }

2. Полагая, что программа передает тестовые данные, вы задаете параметр

open_mode
из следующих аргументов:

 for(i = 1; i <argc; i++) {

if (strncmp(*++argv, "O_RDONLY", 8) == 0) open_mode |= O_RDONLY;

if (strncmp(*argv, "O_WRONLY", 8) == 0) open_mode |= O_WRONLY;

if (strncmp(*argv, "O_NONBLOCK", 10) == 0) open_mode |= O_NONBLOCK;

 }

3. Далее проверьте, существует ли канал FIFO, и при необходимости создайте его. Затем FIFO открывается, и пока программа засыпает на короткое время, выполняется результирующий вывод. В заключение FIFO закрывается.

 if (access(FIFO_NAME, F_OK) == -1) {

res = mkfifo(FIFO_NAME, 0777);

if (res != 0) {

fprintf(stderr, "Gould not create fifo %s\n", FIFO_NAME);

exit(EXIT_FAILURE);

}

 }

 printf("Process %d opening FIF0\n", getpid);

 res = open(FIFO_NAME, open_mode);

 printf("Process %d result %d\n", getpid, res);

 sleep(5);

 if (res != -1) (void)close(res);

 printf("Process %d finished\n", getpid);

 exit(EXIT_SUCCESS);

}

Как это работает

Эта программа позволяет задать в командной строке комбинации значений

O_RDONLY
,
O_WRONLY
и
O_NONBLOCK
, которые вы хотите применить. Делается это сравнением известных строк с параметрами командной строки и установкой (с помощью
|=
) соответствующего флага при совпадении строки. В программе используется функция
access
, проверяющая, существует ли уже файл FIFO, и создающая его при необходимости.

Поделиться с друзьями: