Никогда не уничтожайте FIFO, т.к. у вас нет способа узнать, не использует ли FIFO другая программа.
O_RDONLY и O_WRONLY без O_NONBLOCK
Теперь у вас есть тестовая программа, и вы можете проверить комбинации пар. Обратите внимание на то, что первая программа, считыватель, помещена в фоновый режим.
$ ./fifo2 O_RDONLY &
[1] 152
Process 152 opening FIFO
$ ./fifo2 O_WRONLY
Process 153 opening FIFO
Process 152 result 3
Process 153 result 3
Process 152 finished
Process 153 finished
Это,
наверное, самое распространенное применение именованных каналов. Оно позволяет читающему процессу стартовать и ждать в вызове
open
, а затем разрешает обеим программам продолжить выполнение, когда вторая программа откроет канал FIFO. Обратите внимание на то, что и читающий, и пишущий процессы были синхронизированы вызовом
open
.
Примечание
Когда процесс в ОС Linux заблокирован, он не потребляет ресурсы ЦП, поэтому этот метод синхронизации очень эффективен с точки зрения использования ЦП.
O_RDONLY с O_NONBLOCK и O_WRONLY
В следующем примере читающий процесс выполняет вызов
open
и немедленно продолжается, даже если нет ни одного пишущего процесса. Пишущий процесс тоже немедленно продолжает выполняться после вызова
open
, потому что канал FIFO уже открыт для чтения.
$ ./fifо2 O_RDONLY O_NONBLOCK &
[1] 160
Process 160 opening fifo
$ ./fifo2 O_WRONLY
Process 161 opening FIFO
Process 160 result 3
Process 161 result 3
Process 160 finished
Process 161 finished
[1]+ Done ./fifo2 O_RDONLY O_NONBLOCK
Эти два примера — вероятно, самые распространенные комбинации режимов
open
. Не стесняйтесь использовать программу-пример для экспериментов с другими возможными комбинациями.
Чтение из каналов FIFO и запись в них
Применение режима
O_NONBLOCK
влияет на поведение вызовов
read
и
write
в каналах FIFO.
Вызов
read
, применяемый для чтения из пустого блокирующего FIFO (открытого без флага
O_NONBLOCK
), будет ждать до тех пор, пока не появятся данные, которые можно прочесть. Вызов
read
, применяемый в неблокирующем FIFO, напротив, при отсутствии данных вернет 0 байтов.
Вызов
write
для записи в полностью блокирующий канал FIFO будет ждать до тех пор, пока данные не смогут быть записаны. Вызов
write
, применяемый к FIFO,
который не может принять все байты, предназначенные для записи, либо:
будет аварийно завершен, если был запрос на запись
PIPE_BUF
байтов или меньше и данные не могут быть записаны;
запишет часть данных, если был запрос на запись более чем
PIPE_BUF
байтов, и вернет количество реально записанных байтов, которое может быть и 0.
Размер FIFO — очень важная характеристика. Существует накладываемый системой предел объема данных, которые могут быть в FIFO в любой момент времени. Он задается директивой
#define PIPE_BUF
, обычно находящейся в файле limits.h. В ОС Linux и многих других UNIX-подобных системах он обычно равен 4096 байт, но в некоторых системах может быть и 512 байт. Система гарантирует, что операции записи PIPE_BUF или меньшего количества байтов в канал FIFO, который был открыт
O_WRONLY
(т.е. блокирующий), запишут или все байты, или ни одного.
Несмотря на то, что этот предел не слишком важен в простом случае с одним записывающим каналом FIFO и одним читающим FIFO, очень распространено использование одного канала FIFO, позволяющего разным программам отправлять запросы к этому единственному каналу FIFO. Если несколько разных программ попытаются писать в FIFO в одно и то же время, жизненно важно, чтобы блоки данных из разных программ не перемежались друг с другом, т. е. каждая операция write должна быть "атомарной". Как это сделать?
Если вы ручаетесь, что все ваши запросы
write
адресованы блокирующему каналу FIFO и их размер меньше
PIPE_BUF
байтов, система гарантирует, что данные никогда не будут разделены. Вообще это неплохая идея — ограничить объем данных, передаваемых через FIFO блоком в
PIPE_BUF
байтов, если вы не используете единственный пишущий и единственный читающий процессы.
Выполните упражнение 13.12.
Упражнение 13.12. Связь процессов с помощью каналов FIFO
Для того чтобы увидеть, как несвязанные процессы могут общаться с помощью именованных каналов, вам понадобятся две отдельные программы fifo3.c и fifo4.c.
1. Первая программа — поставщик. Она создает канал, если требуется, и затем записывает в него данные как можно быстрее.
Примечание
Поскольку пример иллюстративный, нас не интересуют конкретные данные, и мы не беспокоимся об инициализации буфера, В обоих листингах затененные строки содержат изменения, внесенные в программу fifo2.c помимо удаления кода со всеми аргументами командной строки.