我试图更深入地了解C
和stdio
中的缓冲工作原理,并且发现了一些有趣的东西。我读过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
)。
所以说在实际管道缓冲区顶部还有两个缓冲区stdout
和stdin
的缓冲区是正确的吗? setbuf
仅控制这两个缓冲区,而不修改内核管道缓冲区的任何属性。因此,将stdin
设置为n
字节缓冲区意味着它会保留n
字节,然后再返回内核进行read
系统调用。
答案 0 :(得分:2)
缓冲仅存在于libc(您从stdio调用的函数)中。 syscall接口上没有缓冲。如果您进行系统调用(例如使用read
或write
),则在调用内核之前,libc包装程序通常做的很少。
command
必须以...使用ISO C FILE流进行输入/输出的程序名称开头(请注意,程序dd
和cat
请勿这样做),
这是因为stdbuf
works通过将库预加载到目标程序中而更改了缓冲模式(在其libc中)。直接进行系统调用的程序不受影响。
stdbuf
并未更改内核中管道缓冲区的大小。该缓冲区与libc提供的缓冲无关。
stdio本质上是否维护自己的缓冲区,并且stdbuf -i3表示一次从内核中的主管道缓冲区读入该缓冲区3个字节?
是的。 Libc为stdio.h FILE
流提供了缓冲区。