来自Linux手册页:
vfork()
函数具有与fork(2)
相同的效果,只是如果进程[…]在成功调用exec(3)
函数族中的[…]函数之前调用了任何其他函数,则行为未定义。
这表明在vfork()
之后调用任何exec*()
函数都是可以接受的。然而,在稍后的手册页中,它特别指出:
特别是,程序员不能依赖父级保持阻塞,直到子级[…]调用
execve(2)
[…]。
execve(2)
在手册页中被重复使用,它的用法表明它是继vfork()
之后唯一可以接受的exec
类型的函数。
那么,为什么execve
在这里被单独列出,我可以安全地调用其他exec
类型的函数(如execlp
(吗?
您必须调用execve
。不能保证任何其他exec家族函数在vfork
之后都不会执行不安全的操作。例如:
-
CCD_ 15可以为参数列表分配存储器。它需要是异步信号安全的,这意味着它不太可能使用
malloc
,但即使不使用,在底层execve
发生后,它也不可能释放分配的内存(存在于父级的内存空间中(,因此它(最多(会泄漏父级中的内存,除非它设法在堆栈上构造参数列表。 -
execvp
需要访问环境来执行路径搜索,还需要构建连接的路径名以传递给execve
。后者可能需要分配,而前者可能在-vfork
之后做各种不安全的事情(注意: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都允许在vfork
之后调用execve
(并且只有execve
*(。POSIX标准可能允许其他exec
函数,但Linux不允许。
*当然,它也可以调用_exit
,但我在这个问答中忽略了_exit
;A.