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 помимо удаления кода со всеми аргументами командной строки.
Читать дальше