我有以下情况。
我创建了一个管道。
分叉一个子进程。
Child关闭管道的读取结束并写入管道的写入端并退出而不关闭任何东西(exit应该代表子代关闭所有打开的文件/管道描述符, 我相信)。
Parent显式关闭管道的写入端,并使用fgets
从管道的读取端读取,直到fgets
返回NULL。即完全读完。
现在我的问题是,为什么父母需要在读完后明确地关闭管道的读取端?一旦从读端读取完整的数据,系统是否完全删除管道是不明智的?
我在父节目中明确地关闭了读取端,并且在打开更多管道时迟早会出现Too many file descriptors
错误。我的假设是,一旦管道写入结束并且数据已从读取端完全读取,系统会自动删除管道。你有两次从管道出来了吗?
那么,一旦数据被完全读取并写入结束,系统背后的理由是不删除管道?
答案 0 :(得分:7)
你是正确的,一旦孩子退出,系统将关闭管道的写端。但是,如果子fork
或者将写端的副本传递给另一个进程,则该管道的另一个写端可能会打开。
系统仍然可以判断管道一端的所有描述符何时被关闭(显式或因为退出拥有过程)。关闭管道另一端的那些仍然没有意义,因为当父进程试图关闭管道末端的描述符时会导致混淆;之一:
从系统的角度来看,一旦所有描述符都被关闭,它可能会丢弃管道,所以你不必担心那里的效率低下。更重要的是,用户空间进程应该具有一致的体验,这意味着除非特别要求,否则不会关闭描述符。
答案 1 :(得分:5)
系统不会关闭文件描述符,直到进程退出。对于管道以及任何其他文件描述符都是如此。
没有数据的管道(或任何其他文件)与封闭的文件描述符之间存在很大差异。
关闭文件描述符时,系统可以将其编号重用于新的文件描述符。然后,当你读,你会得到别的东西。因此,在关闭文件描述符后,您必须不再使用它。
现在想象一下,一旦没有更多数据,系统就会自动关闭文件描述符。这将使该数量可供重用,并且随后的无关打开可以获得它。现在,那个还不知道没有更多数据的读者会从它认为是管道的内容中读取,但实际上会读取另一个文件。