10

我有以下情况。

  1. 我创建了一个管道。

  2. 分叉了一个子进程。

  3. 子进程显式关闭管道的读取端并写入管道的写入端并退出而不关闭任何东西(我认为 exit 应该代表子进程关闭所有打开的文件/管道描述符)。

  4. Parent显式关闭管道的写入端,并使用fgetsuntilfgets返回 NULL从管道的读取端读取。即它完全读取。

现在我的问题是,为什么父级在完成读取后需要明确关闭管道的读取端?从读取端读取完整数据后,系统完全删除管道不是明智的吗?

我在父项中明确关闭了读取端,并且Too many file descriptors在打开更多管道时迟早会出错。我的假设是,一旦管道的写入端关闭并且数据已从读取端完全读取,系统会自动删除管道。因为你不能从管道中两次!

那么,一旦数据完全读写结束,系统不删除管道的原因是什么?

4

2 回答 2

7

您是正确的,一旦孩子退出,系统将关闭管道的写入端。但是,如果子forks 或将写入端的副本传递给另一个进程,则该管道的另一个写入端可能打开。

系统仍然可以判断管道一端的所有描述符何时已关闭(显式关闭或因为拥有进程退出)。关闭管道另一端的描述符仍然没有意义,因为当父进程试图关闭管道另一端的描述符时会导致混乱;任何一个:

  • fd 已被系统关闭,在这种情况下,当它试图关闭已关闭的 fd 时会出现错误;或者
  • fd 已被重用,更糟糕的是,它现在正在关闭一个完全不相关的 fd。

从系统的角度来看,一旦关闭了一端的所有描述符,它很可能已经丢弃了管道,因此您不必担心那里的效率低下。更重要的是用户空间进程应该有一致的体验,这意味着除非特别要求,否则不要关闭描述符。

于 2012-08-06T10:32:10.457 回答
5

文件描述符不会被系统关闭,直到进程退出。对于管道以及任何其他文件描述符都是如此。

没有数据的管道(或任何其他文件)与关闭的文件描述符之间存在很大差异。
当文件描述符关闭时,系统可以将其编号重新用于新的文件描述符。然后,当您阅读时,您会得到其他东西。所以在你关闭了一个文件描述符之后,你就不能再使用它了。

Now imagine that once there's no more data, the system would automatically close the file descriptor. This would make the number available for reuse, and a subsequent unrelated open may get it. Now the reader, who doesn't know yet that there's no more data, will read from what it thinks is the pipe, but will actually read from another file.

于 2012-08-06T10:38:12.547 回答