我需要刷新命名管道吗?

Do I need to flush named pipes?

我找不到命名管道是否被缓冲,因此出现了这个问题。

联机帮助页说 https://linux.die.net/man/3/mkfifo:

A FIFO special file is similar to a pipe ... any process can open it for reading or writing, in the same way as an ordinary file.

管道没有缓冲,不需要冲洗。但在普通文件中,我会 fflush(或 fsync)文件描述符。

命名管道怎么样?

Pipes are not buffered, no need to flush.

我实际上会反过来说:对于 most 意图和 purposes,管道 只不过是 缓冲区。刷新它们没有意义,因为没有底层设备接收数据。

此外,虽然 POSIX 没有明确禁止管道的额外缓冲 I/O,但它确实提出了足够的行为要求,我认为没有任何方法可以通过观察来确定是否这样缓冲发生,除了 possibly 是否 fsync() 成功。换句话说,即使有额外的缓冲,也不应该fsync()一个管道结束。

But in a ordinary file, I would fflush (or fsync) the file descriptor.

不,你不会 fflush() 文件描述符。 fflush() 上运行,由 FILE 对象表示,而不是在文件描述符上。这是一个关键的区别,因为 most 流在 C 库级别进行缓冲,与底层文件的性质无关。 fflush() 与之交互的正是这个库级缓冲区。您可以通过 setvbuf() 函数控制流的库级缓冲模式。

在提供它的ose 系统上,fsync() 在不同的较低级别上运行。它指示 OS 确保之前写入指定文件描述符的所有数据都已传送到底层存储设备。换句话说,它会刷新 OS 级缓冲区。

请注意,您可以通过 fdopen() 函数将流包装在管道端文件描述符周围。这不会使 管道 比以前更需要刷新,但是 默认情况下会被缓冲,因此刷新是相关的

另请注意,某些存储设备执行自己的缓冲,因此即使数据已移交给存储设备,也不确定它们是否会立即持久化。

How about named pipe?

上面关于流的讨论I/Ovs。 POSIX 基于描述符的 I/O 也适用于此。如果您通过流访问命名管道,那么它与 fflush() 的交互将取决于该流的缓冲。

但我支持os你的问题更多是关于 os 级别的缓冲和刷新。 POSIX 似乎并没有说太多具体的内容,但是由于您标记了 [linux] 并在您的问题中参考了 Linux 手册页,因此我提供以下回复:

The only difference between pipes and FIFOs is the manner in which they are created and opened. Once these tasks have been accomplished, I/O on pipes and FIFOs has exactly the same semantics.

(Linux pipe(7) manual page.)

我不太明白你想问什么,但正如你已经被告知的那样,管道不仅仅是缓冲区。

历史上,fifos(或管道)消耗用于维护它们的 inode 的直接块,并且它们绑定到某些文件系统中的文件(有或没有名称)。

今天,我不知道 fifo 的确切实现细节,但基本上,内核会缓冲写入器已经写入但 reader 尚未读取的所有数据。 fifo 对它们可以支持的缓冲区数量有上限(系统定义),但通常在 10-20kb 左右的数据时会失败。

内核缓冲区,但是写入器和 readers 之间没有延迟,因为一旦写入器在管道上写入,内核就会唤醒所有等待它获取数据的 readers .反之亦然,在管道充满数据的情况下,一旦 reader 消耗它,所有的写入器都会被唤醒以允许再次填充它。

无论如何,你关于冲洗的问题与管道无关(好吧,不像,让我自己解释一下),而是与 <stdio.h> 包有关。 <stdio.h> 缓冲,并且它单独处理每个 FILE * 上的缓冲,所以当你希望它们是 write(2)n 时,你可以调用刷新缓冲区到磁盘。

有一个动态行为,允许优化缓冲,而不是强迫程序员每次都必须刷新。这取决于与 FILE * 指针关联的文件描述符的类型。

FILE * 指针与串行 tty 相关联时(它会检查调用 isatty(3) 调用,它在内部进行 ioctl(2) 调用,允许 <stdio.h> 看看你是否反对一个串行设备,一个字符设备。如果发生这种情况,那么 <stdio.h>行缓冲 这意味着总是当一个 '\n' 字符输出到设备,缓冲区自动缓冲。

这假设是一个优化问题,因为例如当您使用 cat(1) 复制文件时,最大的缓冲区通常假设是最有效的方法。好吧,<stdio.h>来解决这个问题,因为当output不是tty设备时,它会做full buffering,只有当FILE *指针的内部缓冲区满了数据时才刷新

所以问题是:<stdio.h> 如何处理 fifo(或管道)节点?答案很简单……不是字符设备(或 tty),因此 <stdio.h> 对其进行完全缓冲。如果您在两个进程之间传递数据并且您希望 reader 在您 printf(3) 编辑数据后立即接收数据,那么您最好 fflush(3),因为如果您不这样做t,你可以等待一个永远不会到来的响应,因为你写的东西,还没有被写(不是内核,而是<stdio.h>库)

正如我所说,我不知道这是否正是您问题的答案,但可以肯定的是,它可以给您提示问题可能出在哪里。