setbuf仅影响stdio调用,不影响系统调用?

时间:2019-07-16 02:14:56

标签: c pipe stdio

我试图更深入地了解Cstdio中的缓冲工作原理,并且发现了一些有趣的东西。我读过this文章,但想确认自己理解正确。

当我使用fgets时,将输入缓冲设置为3个字节(stdbuf -i3)并检查strace,我看到读取以3个字符为一组,这是我期望的:

read(0, "hel", 3)                       = 3
read(0, "lo\n", 3)                      = 3
...

如果我仍然使用stdbuf,但是这次我改为使用read(2)系统调用,它将立即读取全部内容(最多4096字节):

read(0, "hello\nworld!\n\n", 4096)      = 14

因此它忽略了stdbuf调用。

这使我完全重新考虑stdio缓冲。 stdio是否实质上维护了自己的缓冲区,并且stdbuf -i3是说要一次从内核中的主管道缓冲区读入该缓冲区3个字节?我认为执行stdbuf -i0会使管道的容量无法容纳一个以上的字节(即write(2)的调用会在将stdout发送到进程的无缓冲stdin)。

所以说在实际管道缓冲区顶部还有两个缓冲区stdoutstdin的缓冲区是正确的吗? setbuf仅控制这两个缓冲区,而不修改内核管道缓冲区的任何属性。因此,将stdin设置为n字节缓冲区意味着它会保留n字节,然后再返回内核进行read系统调用。

1 个答案:

答案 0 :(得分:2)

缓冲仅存在于libc(您从stdio调用的函数)中。 syscall接口上没有缓冲。如果您进行系统调用(例如使用readwrite),则在调用内核之前,libc包装程序通常做的很少。

documentation for stdbuf

  

command必须以...使用ISO C FILE流进行输入/输出的程序名称开头(请注意,程序ddcat请勿这样做),

这是因为stdbuf works通过将库预加载到目标程序中而更改了缓冲模式(在其libc中)。直接进行系统调用的程序不受影响。

stdbuf并未更改内核中管道缓冲区的大小。该缓冲区与libc提供的缓冲无关。


  

stdio本质上是否维护自己的缓冲区,并且stdbuf -i3表示一次从内核中的主管道缓冲区读入该缓冲区3个字节?

是的。 Libc为stdio.h FILE流提供了缓冲区。