我找不到命名管道是否被缓冲,因此问题。
该联机帮助页显示https://linux.die.net/man/3/mkfifo:
FIFO特殊文件类似于管道...任何进程都可以打开它进行读取或写入,方式与普通文件相同。
管道没有缓冲,不需要冲洗。但在普通文件中,我会fflush(或fsync)文件描述符。
命名管道怎么样?
答案 0 :(得分:5)
管道没有缓冲,不需要冲洗。
我实际上反过来说:对于大多数意图和目的,管道只是缓冲区。刷新它们没有意义,因为没有底层设备可以接收数据。
此外,尽管POSIX没有明确禁止管道I / O的额外缓冲,但它确实提供了足够的行为要求,我认为没有任何方法可以从观察中确定是否发生了这种缓冲,除了可能是fsync()
是否成功。换句话说,即使有额外的缓冲,也不需要fsync()
管道末端。
但在普通文件中,我 将fflush(或fsync)文件描述符。
嗯不,你不会fflush()
一个文件描述符。 fflush()
在 streams 上运行,由FILE
个对象表示,而不是文件描述符。这是一个至关重要的区别,因为大多数流都在C库级别进行缓冲,与下面文件的性质无关。这是fflush()
与之交互的库级缓冲区。您可以通过setvbuf()
函数控制流的库级缓冲模式。
在提供它的系统上,fsync()
在不同的较低级别运行。它指示操作系统确保先前写入指定文件描述符的所有数据都已传送到底层存储设备。换句话说,它会刷新OS级缓冲区。
请注意,您可以通过fdopen()
函数将流包装在管道末端文件描述符周围。这不会使管道需要比以前更多地进行刷新,但流将默认缓冲,因此刷新将与之相关。 / p>
另请注意,某些存储设备会执行自己的缓冲,因此即使将数据传递给存储设备,也无法确定它们是否会立即持续存在。
命名管道怎么样?
上面关于流I / O vs 的讨论。基于POSIX描述符的I / O也适用于此处。如果您通过流访问命名管道,那么它与fflush()
的交互将取决于该流的缓冲。
但我想你的问题更多的是os级缓冲和刷新。 POSIX似乎没有说明具体的内容,但是由于您在标题中标记了[linux]并参考了Linux手册页,我提供了以下内容:
管道和FIFO之间的唯一区别在于它的方式 它们被创建和打开。完成这些任务后, 管道和FIFO上的I / O具有完全相同的语义。
答案 1 :(得分:1)
我不太清楚你想要问什么,但正如你已经被告知的那样,管道只不过是缓冲。
历史上,fifos(或管道)消耗了用于维护它们的inode的直接块,并且它们绑定到某个文件系统中的文件(有或没有名称)。
今天,我不知道fifo的具体实现细节,但基本上,内核会缓冲编写器已经编写的所有数据,但读者还没有读过。 fifo有一个上限(系统定义),表示它们可以支持的缓冲区数量,但通常会在10-20kb的数据范围内失败。
内核缓冲区,但是编写器和读取器之间没有延迟,因为只要编写器在管道上写入,内核就会唤醒所有等待它获取数据的读者。反过来也是如此,在管道充满数据的情况下,一旦读者消费它,所有的作者都被唤醒以允许再次填充它。
无论如何,你关于冲洗的问题与管道无关(好吧,不是,让我自己解释一下),而是使用<stdio.h>
包。 <stdio.h>
执行缓冲区,并且它会分别处理每个FILE *
上的缓冲,因此当您希望它们为write(2)
n到磁盘时,您可以调用刷新缓冲区。
具有动态行为,允许优化缓冲,而不是强迫程序员每次都必须刷新。这取决于与FILE *
指针关联的文件描述符的类型。
当FILE *
指针与序列tty相关联时(它会检查调用isatty(3)
调用,该调用在内部进行ioctl(2)
调用,允许<stdio.h>
看看你是否反对串行设备,一个字符设备。如果发生这种情况,那么<stdio.h>
进行行缓冲,这意味着总是将'\n'
字符输出到设备,缓冲区自动缓冲。
这假设了一个优化问题,因为例如,当您使用cat(1)
复制文件时,缓冲区通常假设最有效的方法。好吧,<stdio.h>
来解决这个问题,因为当输出不是tty设备时,它会进行完全缓冲,并且只有当FILE *
指针充满数据时才会刷新内部缓冲区。
所以问题是:<stdio.h>
如何使用fifo(或管道)节点?答案很简单....不是char设备(或tty)所以<stdio.h>
对它进行完全缓冲。如果您要在两个流程之间传递数据,并且希望读者在printf(3)
编辑数据后尽快收到数据,那么您最好fflush(3)
,因为如果您不这样做,你可以等待一个永远不会发生的回应,因为你所写的,尚未编写(不是由内核编写,而是由<stdio.h>
库编写)
正如我所说的,我不知道这是否正是你问题的答案,但肯定能给你一个问题所在的暗示。