C中的管道,用于读取标准输入的缓冲区

Posted

技术标签:

【中文标题】C中的管道,用于读取标准输入的缓冲区【英文标题】:Pipes in C, buffer for reading stdin 【发布时间】:2022-01-12 05:12:22 【问题描述】:

我正在努力理解这个this answer。尤其是数据如何跨进程流动?

我假设输入流通过与管道连接的输出流经孩子的输入,然后由父通过管道输出收集。但是,在新一轮循环并在子进程中执行命令之前,读取的数据会发生什么变化?

数据是否在父进程内部缓冲(不知何故?我想知道是什么原因造成的),稍后这个缓冲区被复制并在fork()之后传递给子进程,然后子进程将保存的输入传递给exec()?

编辑 - 附加方面:

(在我提供的示例中,循环的每一圈都会创建新管道,并在调用 pipe() 时填充新的描述符。我创建了一个工作修改,其中表描述符的数量在循环外创建并重新填充。它如何影响从先前执行的命令中读取的数据?它存储在哪里,何时创建新管道并将新文件描述符存储在重用表中?)

【问题讨论】:

【参考方案1】:

有一个与管道关联的缓冲区。

如果缓冲区未满,写入将返回,程序将继续。

但是缓冲区有可能被填满。如果写入无法完成,它将导致部分写入(提供写入的数量)或阻塞直到写入完成(即当某物最终从另一端读取时)。

试图从空管道读取的读取器通常会阻塞,直到数据可用。如果描述符被设为非阻塞,则读取将返回错误 EWOULDBLOCK 或 EAGAIN。

select 和类似的机制可用于检测何时可以安全地执行无阻塞的读取或写入。

管道的每一端都可以独立关闭。仅在关闭文件描述符的所有副本后才关闭结尾。这包括继承的副本。一个常见的场景是子级从其父级继承管道。父级将关闭其描述符之一,而子级将关闭另一个。这使得一个进程能够写入管道,而另一个进程能够从中读取。 (双向通信需要两个管道或一个套接字。)

如果阅读器退出会发生什么?默认情况下,写入封闭管道会产生 SIGPIPE 信号。默认情况下,这会终止写入过程。这通常非常有用。例如,考虑在很长的流上使用head 的情况。但它并不总是有用的。有时,您想检测并处理这种情况。幸运的是,通过使用通常的机制处理或忽略信号,这是完全可配置的。如果忽略,写入操作将失败并返回错误代码 EPIPE。

系统之间的行为会有所不同。例如,Windows 没有信号*,select 不适用于管道。 (不过,它确实适用于套接字。)但它也提供了执行异步 I/O 的替代方法。

【讨论】:

在我展示的示例中,当调用pipe() 时,循环的每一圈都会创建新管道并填充新的描述符。我创建了一个工作修改,其中描述符表在循环外部创建并重新填充。它如何影响先前执行的命令中先前读取的数据? 我对我的后续问题有一个想法:新管道是在同一个表中创建的,但旧管道没有被破坏 - 那是数据在等待的地方,在以前的管道。新一轮循环中的子节点从父节点继承描述符表——在这个描述符表中,有重复的先前管道的读取描述符。子进程复制父进程未更改的写入描述符,并将输出重定向到新创建的管道。 (超出字母限制)但是,在引用问题的 cmets 中,建议使用 close(pipe[0])。它如何影响在下一轮循环中从前一个管道读取数据? OK,描述符表中的描述符还没有关闭,所以我们可以从之前的管道中读取。

以上是关于C中的管道,用于读取标准输入的缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

while(cin)是啥意思(C++)

Linux C程序获取本机可用IP地址 && Linux C程序获取system()函数的标准输出到char *缓冲中

fflush和标准输入与输出

fflush和标准输入与输出

xargs命令详解,xargs与管道的区别

C中的进程间通信