Я пытаюсь заполнить именованный канал (созданный mkfifo /tmp/pipe
), записывая в него 3 байта за раз до тех пор, пока функция write()
не заблокируется.
В моей системе канал ограничен 16 страницами по 4096 байт. Таким образом, канал может содержать 65536 байт.
Я делаю это с помощью следующего кода C:
int main ()
{
pid_t child;
child = fork ();
if (child == 0)
{
ssize_t ret;
ssize_t total = 0;
unsigned char *datat = malloc (65536);
assert (datat != NULL);
int fd = open ("/tmp/pipe", O_WRONLY);
assert (fd != -1);
while (1)
{
printf ("Trying writting\n");
ret = write (fd, datat, 3);
assert (ret != -1);
total += ret;
printf ("write : %ld.\n", total);
}
}
else
{
int fd = open ("/tmp/pipe", O_RDONLY);
assert (fd != -1);
while (1); //prevent closing the pipe.
}
return 0;
}
Таким образом, мне удается заполнить трубу до 65520 байт. Я не понимаю, почему 65520, а не 65536 (или 65535, если учесть, что 65536 не делится на 3).
Затем я попытался записать 65520 байт и после этого записать 3 байта:
int
main (int argc, char *argv[])
{
pid_t child;
child = fork ();
if (child == 0)
{
ssize_t ret;
ssize_t total = 0;
unsigned char *datat = malloc (65536);
assert (datat != NULL);
int fd = open ("/tmp/pipe", O_WRONLY);
assert (fd != -1);
while(1)
{
printf ("Trying writting\n");
ret = write (fd, datat, 65520);
assert (ret != -1);
total += ret;
printf ("Trying writting\n");
ret = write (fd, datat, 3);
assert (ret != -1);
total += ret;
printf ("write : %ld.\n", total);
}
}
else
{
int fd = open ("/tmp/pipe", O_RDONLY);
assert (fd != -1);
while (1); //prevent closing the pipe.
}
return 0;
}
Я ожидал второй записи в блок, но этого не произошло, и я написал 65523 байта.
Возникает вопрос: почему я не могу записать больше 65520 байт в первом случае, а я могу во втором?
Обновлено:
Больше информации :
Моя операционная система - Linux archlinux 4.16.5-1-ARCH
man 7 pipe
дает информацию о размере (который равен 65536 байтам) канала и подтверждается fcntl:
int
main (int argc, char *argv[])
{
int fd = open ("/tmp/pipe", O_WRONLY);
printf ("MAX : %d\n", fcntl (fd, F_GETPIPE_SZ));
return 0;
}
"вы не показали нам, как вы создаете" / tmp / pipe ". Я сделал: я использовал команду mkfifo." В моей системе канал, кажется, ограничен 16 страницами по 4096 байт. ": Я отредактировал вопрос для что.
Также у меня такое же поведение с классической (безымянной) трубой.
Это связано с тем, как страницы размером 4 КБ заполняются записанными данными в реализации конвейера в ядре Linux. В частности, ядро добавляет записанные данные на страницу только в том случае, если данные полностью помещаются на странице, в противном случае помещает данные на другую страницу с достаточным количеством свободных байтов.
Если вы записываете 3 байта за раз, страницы канала не будут заполнены на полную мощность, потому что размер страницы (4096) не кратен 3: ближайшее кратное 4095, поэтому каждая страница будет иметь 1 "потраченный впустую" байт. Умножив 4095 на 16, то есть общее количество страниц, вы получите 65520.
Во втором варианте использования, когда вы записываете 65520 байт за один раз, вы полностью заполняете 15 страниц (61440 байт), плюс вы помещаете оставшиеся 4080 байт на последнюю страницу, на которой будет доступно 16 байт для последующих записей: вот почему ваш второй вызов write () с 3 байтами завершается успешно без блокировки.
Для получения полной информации о реализации конвейера Linux см. https://elixir.bootlin.com/linux/latest/source/fs/pipe.c.
Это две ключевые недостающие информации в вашем вопросе, который вы не доказали нам, что «В моей системе канал, кажется, ограничен 16 страницами по 4096 байтов». плюс, вы не показали нам, как вы создаете "/ tmp / pipe". А с классическим
pipe()
пробовали?