execve() 和共享文件描述符

Posted

技术标签:

【中文标题】execve() 和共享文件描述符【英文标题】:execve() and sharing file descriptors 【发布时间】:2011-03-11 21:55:51 【问题描述】:

我从 execve 的手册页中了解到,如果进程 (A) 调用 execve,则已打开的文件描述符将复制到新进程 (B)。

这里有两种可能性:-

1) 是否意味着为进程B创建了一个新的文件描述符表,其中的条目是从进程A的旧文件描述符表中复制而来的

2) 或者进程 B 获取进程 A 的文件描述符表,因为在 execve 之后进程 A 将不复存在,并且已经打开的文件只能从进程 B 关闭,如果它获取进程 A 的文件描述符表。

哪个是正确的?

【问题讨论】:

【参考方案1】:

哪个是正确的?

#2

尽管您询问的更多的是操作系统实现细节,而这对应用程序来说几乎没有重要意义,但对应用程序完全透明并且取决于操作系统。

通常说新进程继承文件描述符。显然,那些设置了 FD_CLOEXEC 标志的除外。

即使在 #1 的情况下,如果我们假设进程 A 和 B 都在内存中(不是真的,那是 fork() 领域)在短时间内复制 fd 表是可以的。由于进程 A 将被终止(由 exec()),它的所有文件描述符都将是 close()d。这对进程 B 中已经复制的文件描述符没有影响。文件描述符就像指向相应内核结构的指针,其中包含有关文件描述符实际指向的实际信息。复制 fd 表不会复制底层结构 - 它只复制指针。内核结构包含引用计数器(实现 fork() 所需的),它在复制时递增,因此知道有多少进程正在使用它。首先在文件描述符上调用 close() 会减少引用计数器。并且只有当计数器变为零(没有更多进程正在使用该结构)时,操作系统才会真正关闭底层文件/套接字/管道/等。 (但很明显,即使内核内部有两个进程同时存在一段时间,用户空间应用程序也看不到这一点,因为 exec() 之后的新进程也继承了原始进程的 PID。)

【讨论】:

第二段是最好的(“inherits”文件描述符)。我在读到最后一段时迷路了。【参考方案2】:

execve 不会创建新进程。它根据文件系统中的可执行文件将调用进程的程序映像、内存空间等替换为新的。通过关闭任何设置了 close-on-exec 标志的描述符来修改文件描述符表;其余部分保持打开状态,并处于execve 之前的相同状态(当前位置、锁定等)。

您可能将此与fork 上发生的事情混淆了,因为execve 通常以fork 开头。当一个进程分叉时,子进程有一个新的文件描述符表,它引用与父进程的文件描述符表相同的打开文件描述。

【讨论】:

我认为这是@***.com 的一个严重限制,虽然两个答案都是正确的,但我只能将其中一个标记为绿色。 @Ashish 现在你可以给他们两个投票了。您现在可能想将此标记为已接受的答案。

以上是关于execve() 和共享文件描述符的主要内容,如果未能解决你的问题,请参考以下文章

python 演示跨进程共享文件描述符

文件描述符表和系统调用

Linux-close_on_exec标志位

Linux中的文件描述符

(2.5)文件和目录操作——Linux文件共享

Linux系统编程---dup和dup2详解