fatal("Can't read response from server");
printf("%d\n", resp.seqNum);
exit(EXIT_SUCCESS);
}
pipes/fifo_seqnum_client.c
Как отмечалось ранее, при открытии очереди FIFO процесс блокируется, если другой ее конец еще не был открыт. Иногда такая блокировка является нежелательной, и для этих случаев при вызове open() можно указать флаг O_NONBLOCK:
fd = open("fifopath", O_RDONLY | O_NONBLOCK);
if (fd == -1)
errExit("open");
Если другой конец очереди уже открыт, то флаг O_NONBLOCK никак не влияет на вызов open() — очередь сразу же успешно открывается, как обычно. Действие этого флага проявляется только в случае, если другой конец очереди FIFO еще не открыт, и зависит оно от того, какой именно конец открывается — считывающий или записывающий:
• если очередь FIFO открывается для чтения и ни один процесс не подключен к ее записывающему концу, то вызов open() сразу же успешно завершается (как будто другой конец уже был открыт);
• если очередь FIFO открывается для записи и ни один процесс не подключен к ее считывающему концу, то вызов open() завершается ошибкой ENXIO.
Асимметричность флага O_NONBLOCK, зависящая от того, какой конец очереди FIFO открывается, можно объяснить следующим образом. При открытии очереди для чтения отсутствие записывающего процесса не является проблемой, поскольку любая попытка чтения из очереди просто не возвращает никаких данных. Но если попытаться записать в очередь, к которой не подключен считывающий процесс, то вызов write() приведет к получению сигнала SIGPIPE и ошибки EPIPE.
В табл. 44.1 описывается семантика открытия очереди FIFO, в том числе и с учетом флага O_NONBLOCK, описанного выше.
Таблица 44.1. Семантика вызова open() для очереди FIFO
Тип open()
Результат вызова open()
Открытие для
Дополнительные флаги
Другой конец FIFO открыт
Другой конец FIFO закрыт
Чтение
Нет (блокировка)
Сразу же успешно завершается
Блокируется
O_NONBLOCK
Сразу же успешно завершается
Сразу же успешно завершается
Запись
Нет (блокировка)
Сразу же успешно завершается
Блокируется
O_NONBLOCK
Сразу же успешно завершается
Выдается ошибка (ENXIO)
Использование флага O_NONBLOCK при открытии очередей FIFO служит двум основным целям:
• позволяет одному процессу открыть оба конца очереди. Сначала процесс открывает считывающий конец, указывая флаг O_NONBLOCK, и затем открывает конец для записи;
• предотвращает взаимную блокировку процессов, которые открывают две очереди FIFO.
Рис. 44.8.
Флаг O_NONBLOCK способен влиять на семантику не только вызова open(), но и последующих операций read() и write(), так как продолжает действовать для открытого файлового дескриптора. Мы рассмотрим это влияние в следующем разделе.
Но иногда нужно изменить состояние флага O_NONBLOCK для очереди FIFO (или файла другого типа). Такая необходимость может возникнуть в следующих случаях.
• Очередь FIFO открыта с флагом O_NONBLOCK, но мы хотим, чтобы последующие вызовы read() и write() выполнялись в блокирующем режиме.
• Мы хотим включить неблокирующий режим для файлового дескриптора, возвращенного вызовом pipe(). Если взять более универсальный случай, может возникнуть необходимость изменить неблокирующее состояние любого файлового дескриптора, полученного любым способом, кроме как из вызова open(). Например, это может быть дескриптор, возвращенный вызовом socket(), или один из трех стандартных дескрипторов, которые автоматически открываются для каждой программы, запускаемой из командной оболочки.
• Логика нашего приложения может потребовать установки и сброса флага O_NONBLOCK для какого-нибудь файлового дескриптора.