我尝试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;
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,我成功填充管道直到65520字节.我不明白为什么65520而不是65536(如果我们认为65536不是3的倍数,则为65535).
然后我尝试写入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;
}
Run Code Online (Sandbox Code Playgroud)
我期望第二次写入阻止,但事实并非如此,我写了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;
}
Run Code Online (Sandbox Code Playgroud)
这是因为 Linux 内核中管道实现中 4KB 页面填充写入数据的方式。更具体地说,仅当数据完全适合该页时,内核才会将写入的数据附加到该页,否则将数据放入具有足够空闲字节的另一个页中。
如果一次写入 3 个字节,管道页面将不会被填满,因为页面大小 (4096) 不是 3 的倍数:最接近的倍数是 4095,因此每个页面最终都会有 1 “浪费”字节。将 4095 乘以 16(即总页数),得到 65520。
在第二个用例中,当您一次写入 65520 字节时,您将完全填充 15 个页面(61440 字节),并且您将剩余的 4080 字节放入最后一页,这将有 16 个字节仍可用于后续写入:这就是为什么你的第二个 3 个字节的 write() 调用成功而没有阻塞。
有关 Linux 管道实现的完整详细信息,请参阅https://elixir.bootlin.com/linux/latest/source/fs/pipe.c。
| 归档时间: |
|
| 查看次数: |
368 次 |
| 最近记录: |