当我调用vfork(),我可以调用任何exec *()函数,或者我必须调用execve()?

从Linux手册页 :

vfork()函数与fork(2)具有相同的效果,除了如果进程在成功调用exec(3)系列之一之前调用任何其他函数,行为是未定义的function。

这表明在vfork()之后调用任何exec*()函数是可以接受的。 不过,在手册页的后面具体说到:

尤其是,程序员不能依靠父母继续阻塞,直到子女调用execve(2) […] […]。

execve(2)在man手册中反复使用,它的用法表明它是vfork()之后唯一可以接受的exec -type函数。

那么为什么execve被单挑出来,我可以安全地调用其他exectypes的函数(如execlp )?

你必须调用execve 。 不能保证任何其他exec-family函数都不会执行vfork之后不安全的操作。 例如:

  • execl可能为参数列表分配内存。 它需要是异步信号安全的,这意味着它不太可能使用malloc ,但即使不是这样,在底层execve发生之后,也不可能释放分配的内存(它存在于父内存空间中) ,所以它会(至多)泄漏父内存,除非它设法在栈上构造参数列表。

  • execvp需要访问环境来执行路径搜索,还需要构建连接的路径名传递给execve 。 后者可能需要分配,前者可能会做各种不安全的事情(注意: execvp甚至不是异步信号安全的)。

等等

真的,你应该根本不使用vfork 。 使用安全几乎是不可能的。 特别是在任何使用信号处理程序的程序中都是不安全的,因为信号处理程序可以在共享父内存的情况下在子内运行,除非你阻塞了所有的信号(在这种情况下,子程序将在exec之后继承完全阻塞的信号掩码,几乎肯定不是你想要的)。

如果您正在寻找更有效的fork ,请使用posix_spawn

在Linux上,所有exec*函数实际上都是execve系统调用的封装库函数。 所以通过调用execlp你实际上也调用execve

再次阅读手册后,很明显vfork有两个描述:

POSIX标准描述说,在vfork之后,必须调用其中一个exec(3)函数。

Linux说明说,在vfork之后, execve(2)只有 execve )必须被调用。

我不清楚POSIX标准描述是否需要一个符合的实现来允许任何一个exec函数被调用。 标准描述的一个可能的读法是实现可以决定允许哪个exec函数(并且只要求在vfork之后至少允许其中一个)。

无论哪种方式,很明显Linux允许execve (并且只有execve *)在vfork之后被调用。 POSIX标准可能允许其他的exec函数,但是Linux不支持。

*当然,它也可以调用_exit ,但是我在这个问答中忽略了_exit