从Linux手册页 :
vfork()
函数与fork(2)
具有相同的效果,除了如果进程在成功调用exec(3)
系列之一之前调用任何其他函数,行为是未定义的function。
这表明在vfork()
之后调用任何exec*()
函数是可以接受的。 不过,在手册页的后面具体说到:
尤其是,程序员不能依靠父母继续阻塞,直到子女调用
execve(2)
[…] […]。
execve(2)
在man手册中反复使用,它的用法表明它是vfork()
之后唯一可以接受的exec
-type函数。
那么为什么execve
被单挑出来,我可以安全地调用其他exec
types的函数(如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
。