已经关闭写入端的管道,我们需要显式地关闭读取端吗?

12

我有以下情况:

  1. 创建一个管道。

  2. 分叉一个子进程。

  3. 子进程明确关闭管道的读端并向管道的写端写入数据,并在不关闭任何内容的情况下退出(我认为,exit应该代表子进程关闭所有打开的文件/管道描述符)。

  4. 父进程明确关闭管道的写端,并使用fgets从管道的读端读取,直到fgets返回NULL。即完全读取。

现在我的问题是,一旦完成读取,为什么父进程需要显式关闭管道的读端呢?系统是否应该明智地在完全从读端读取数据后删除管道?

如果我没有在父进程中明确关闭读端,则迟早会出现Too many file descriptors错误,而在打开更多的管道时。我的假设是,系统会自动删除管道,一旦它的写端被关闭并且从读端完全读取了数据。因为你无法再次从管道中读取!

那么,为什么系统在完全读取数据并关闭写端后不删除管道的原理是什么?


因为你不能从一个管道中两次获取数据! - Kerrek SB
@KerrekSB 我的意思是,你可以两次读取同一个管道,但第二次会看到EOF,对吗? - Pavan Manjunath
2个回答

8
您说得对,一旦子进程退出,系统将关闭管道的写入端。但是,如果子进程fork或将写入端的副本传递给另一个进程,则该管道可能还有另一个写入端处于打开状态。
仍然可以确定系统在管道的一端的所有描述符已关闭(无论是显式关闭还是因所属进程退出),这仍然不合理地关闭另一端的描述符,因为当父进程尝试关闭其端的描述符时,这会导致混乱;要么:
- fd已被系统关闭,在这种情况下,尝试关闭已经关闭的fd会出现错误; - 要么fd已被重用,这更糟糕,因为现在正在关闭一个完全不相关的fd。
从系统的角度来看,一旦管道的一端的所有描述符都关闭了,它可能会丢弃该管道,因此您无需担心效率问题。更重要的是,用户空间进程应具有一致的体验,这意味着不应关闭描述符,除非明确请求。

6

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

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

现在想象一下,一旦没有更多的数据,系统会自动关闭文件描述符。这将使编号可供重用,并且随后的不相关的打开可能会得到它。现在读者还不知道没有更多的数据,将从它认为是管道的地方读取,但实际上将从另一个文件中读取。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接