На третьем шаге процесс cat
echo делает доступными некоторые данные, команда cat читает их и выводит в стандартный вывод. Обратите внимание на то, что она затем завершается, не дожидаясь дополнительных данных. Программа cat не блокируется, т.к. канал уже закрылся, когда завершилась вторая команда, поместившая данные в FIFO, поэтому вызовы read в программе cat вернут 0 байтов, обозначая этим конец файла.Теперь, когда вы посмотрели, как ведут себя каналы FIFO при обращении к ним с помощью программ командной строки, давайте рассмотрим более подробно программный интерфейс, предоставляющий больше возможностей управления операциями чтения и записи при организации доступа к FIFO.
В отличие от канала, созданного вызовом pipe
open и close, которые вы ранее применяли к файлам, но с дополнительными функциональными возможностями. Вызову open передается полное имя FIFO вместо полного имени обычного файла.Основное ограничение при открытии канала FIFO состоит в том, что программа не может открыть FIFO для чтения и записи с режимом O_RDWR
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
cat.open(const char *path, O_RDONLY | O_NONBLOCK);
Теперь вызов open
open(const char *path, O_WRONLY);
В данном случае вызов open
open(const char *path, O_WRONLY | O_NONBLOCK);
Этот вариант вызова всегда будет возвращать управление немедленно, но если ни один процесс не открыл этот канал FIFO для чтения, open
Обратите внимание на асимметрию в использовании O_NONBLOCK
O_RDONLY и O_WRONLY, заключающуюся в том, что неблокирующий вызов open для записи завершается аварийно, если ни один процесс не открыл канал для чтения, а неблокирующий вызов open для чтения не возвращает ошибку. На поведение вызова close флаг O_NONBLOCK влияния не оказывает.Выполните упражнение 13.11.