【发布时间】:2011-01-26 14:10:28
【问题描述】:
在 UNIX 环境中的高级编程中阅读有关管道的信息时,我注意到在分叉之后,父级可以close() 管道的读取端,并且它不会关闭子级的读取端。当一个进程分叉时,它的文件描述符会被保留吗?
我的意思是,在分叉之前,管道读取文件描述符的保留计数为 1,在分叉之后为 2。当父关闭其读取端时,fd 变为 1,并为子保持打开状态.这基本上是正在发生的事情吗?常规文件描述符是否也会出现这种行为?
【问题讨论】:
在 UNIX 环境中的高级编程中阅读有关管道的信息时,我注意到在分叉之后,父级可以close() 管道的读取端,并且它不会关闭子级的读取端。当一个进程分叉时,它的文件描述符会被保留吗?
我的意思是,在分叉之前,管道读取文件描述符的保留计数为 1,在分叉之后为 2。当父关闭其读取端时,fd 变为 1,并为子保持打开状态.这基本上是正在发生的事情吗?常规文件描述符是否也会出现这种行为?
【问题讨论】:
答案是肯定的,肯定的(这同样适用于所有文件描述符,包括套接字之类的东西)。
在fork() 调用中,子进程会获得每个文件描述符的单独副本,每个文件描述符的行为都像是由dup() 创建的。 close() 仅关闭传递的特定文件描述符 - 例如,如果您执行 n2 = dup(n); close(n);,则 n 所指的文件(管道、套接字、设备...)保持打开状态 - 这同样适用于由fork() 复制的文件描述符。
【讨论】:
是的,fork 会复制所有打开的文件描述符。
所以对于一个典型的管道,一个2槽数组(int fd[2]),fd[0]对于父子是一样的,fd[1]也是一样。
您可以在完全不分叉的情况下创建管道,并通过在一个进程中使用 fd[0] 和 fd[1] 对自己进行读/写。
【讨论】:
正如人们可以在手册页上看到的那样,fork():
子进程应该有自己的父文件副本 描述符。每个孩子的档案 描述符应指相同的 打开文件描述 对应的文件描述符 父母。
所以是的,孩子拥有父母文件描述符的精确副本,并且指的是所有这些,包括打开的文件。
【讨论】:
fork(),而是它的一个变体。
pthread_atfork 可以将程序在fork 时间的操作更改为(例如)包括关闭文件描述符。但默认情况下不会发生这种情况,无论如何滥用该接口是一件奇怪的事情。