c - 命名管道块在其最大大小之前写入
问题描述
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;
}
解决方案
这是因为 4KB 页面在 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。
推荐阅读
- python - 我应该如何解释或直观地解释我的 CNN 模型的以下结果?
- python - 如何使用图例点击策略在 Python Bokeh 图中隐藏线和圆?
- python - 改组长数组python的快速方法
- react-native - 当prop在React Native Navigation中更改其值时如何更新初始参数
- python - 从日期到元组 Python
- matlab - sympref --- 'MatrixWithSquareBrackets' 不起作用
- python - 由于软件包版本为 0,无法推送到 Heroku
- javascript - Angular 9“没有 ControlContainer 的提供者”VSCode 错误,带有嵌套的表单生成器表单组
- html - 移动浏览器中的后台行为异常
- bash - 在 shell osascript 命令中的“”之间插入一个变量?