□ будет аварийно завершен, если был запрос на запись
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 помимо удаления кода со всеми аргументами командной строки.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
<i>#include <limits.h></i>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
<i>#define BUFFER_SIZE PIPE_BUF</i>
<i>#define TEN_MEG (1024 * 1024 * 10)</i>
int main() {
<i> int pipe_fd;</i>
int res;
int open_mode = O_WRONLY;
<i> int bytes_sent = 0;</i>
<i> char buffer[BUFFER_SIZE + 1];</i>
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
<i> printf("Process %d opening FIFO O_WRONLY\n", getpid());</i>
<i> pipe_fd = open(FIFO_NAME, open_name);</i>
<i> printf("Process %d result %d\n", getpid(), pipe_fd);</i>
<i> if (pipe_fd != -1) {</i>
<i> while (bytes_sent < TEN_MEG) {</i>
<i> res = write(pipe_fd, buffer, BUFFER_SIZE);</i>
<i> if (res == -1) {</i>
<i> fprintf(stderr, "Write error on pipe\n);</i>
<i> exit(EXIT_FAILURE);</i>
<i> }</i>
<i> bytes_sent += res;</i>
<i> }</i>
<i> (void)close(pipe_fd);</i>
<i> } else { </i>
<i> exit(EXIT_FAILURE);</i>
<i> }</i>
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
2. Вторая программа, потребитель, гораздо проще. Она читает и выбрасывает данные из канала FIFO.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
<i>#include <limits.h></i>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
<i>#define BUFFER_SIZE PIPE_BUF</i>
int main() {
<i> int pipe_fd;</i>
int res;
<i> int open_mode = O_RDONLY;</i>
<i> char buffer[BUFFER_SIZE - 1];</i>
<i> int bytes_read = 0;</i>