答案 0 :(得分:35)
vfork
的目的是消除复制整个过程图像的开销,如果你只想在孩子身上做exec*
。因为exec*
替换了子进程的整个图像,所以没有必要复制父进程的图像。
if ((pid = vfork()) == 0) {
execl(..., NULL); /* after a successful execl the parent should be resumed */
_exit(127); /* terminate the child in case execl fails */
}
对于其他类型的用途,vfork
是危险且不可预测的。
对于大多数当前的内核,包括Linux,由于vfork
的实现方式,fork
的主要好处已经消失。而不是在执行fork
时复制整个图像,而是使用写时复制技术。
答案 1 :(得分:23)
如前所述,vfork
手册页清楚地表明了这些差异。
这个topic可以很好地描述fork
,vfork
,clone
和exec
。
以下是我在使用的某些Linux 2.6.3x嵌入式系统上遇到的fork
和vfork
之间经常被忽视的差异。
即使使用写时复制技术,如果没有足够的内存来复制父进程使用的内存,fork
也会失败。例如,如果父进程使用2 GB的驻留内存(即,使用的内存而不仅仅是已分配的内存),如果剩余的可用内存少于2 GB,fork
将失败。当你只想exec
一个简单的程序,因此永远不需要那么大的父地址空间时,这是令人沮丧的!
vfork
没有此内存问题,因为它不会复制父地址空间。子进程更像是一个线程,您可以在其中调用exec*
或_exit
而不会损害您的父进程。
由于内存页表不重复,vfork
比fork
快得多,vfork
的执行时间不受父进程使用的内存量的影响,如指出的那样在这里:http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/
在性能至关重要和/或内存有限的情况下,vfork
+ exec*
因此可以替代fork
+ exec*
。问题是它不太安全,并且人工页面显示vfork
可能会在将来被弃用。
更安全,更便携的解决方案可能是查看posix_spawn
功能,这是更高级别并提供更多选项。尽可能安全地使用vfork
,具体取决于您传递的选项。我已经成功使用posix_spawn
并克服了fork
+ exec
给我的烦恼的“双重内存检查问题”。
A really good page on this topic, with links to some posix_spawn
examples.
答案 2 :(得分:4)
从我的手册页
(来自POSIX.1)vfork()函数 与fork(2)具有相同的效果,除了 如果行为是不确定的 由...创建的过程 vfork()修改除类型变量之外的任何数据 pid_t用于存储返回值 来自vfork(),或者从 调用vfork()的函数,或调用任何其他函数 在成功调用_exit之前(2) 或其中一个exec(3)家族 功能
vfork()与fork(2)的不同之处在于 父母被暂停直到 孩子终止(通常,通过 调用_exit(2),或 异常,在发出致命信号后),或拨打电话 的execve(2)。直到那一点, 孩子与他人共享所有记忆 它的父亲,包括堆栈。孩子一定不能回来 当前函数或调用exit(3), 但可以调用_exit(2)。
答案 3 :(得分:2)
某些系统有一个系统调用vfork(),它最初被设计为fork()的低开销版本。由于fork()涉及复制进程的整个地址空间, 因此非常昂贵,引入了vfork()函数(在3.0BSD中)。
然而,由于引入了vfork(),fork()的实现得到了极大的改进,最引人注目的是引入了“copy-on-write”,其中进程地址空间的复制通过允许两者而被透明地伪造进程引用相同的物理内存,直到它们中的任何一个修改它。这在很大程度上消除了vfork()的理由;实际上,很大一部分系统现在缺乏原有的功能 vfork()完全。但是,为了兼容性,可能仍然存在vfork()调用,它只调用fork()而不尝试模拟所有vfork()语义。
因此,实际使用fork()和vfork()之间的任何差异是非常不明智的。实际上,使用vfork()可能是不明智的,除非你确切知道你想要的原因。
两者之间的基本区别在于,当使用vfork()创建新进程时,父进程将暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状况一直持续到儿童进程 退出或调用execve(),此时父进程继续。
这意味着vfork()的子进程必须小心,以避免意外修改父进程的变量。特别是,子进程不能从包含vfork()调用的函数返回,并且它不能调用exit()(如果需要退出,它应该使用_exit();实际上,对于子进程也是如此正常的fork())。
答案 4 :(得分:1)
答案 5 :(得分:1)
两者之间的基本区别在于,当使用vfork()
创建新进程时,父进程将暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状态一直持续到子进程退出或调用execve()
,此时父进程继续。
这意味着vfork()
的子进程必须小心
避免意外修改父进程的变量。在
特别是,子进程不能从函数返回
包含vfork()
电话,但不得拨打电话
exit()
(如果需要退出,则应使用_exit();
实际上,对于正常fork()
的孩子来说也是如此。
然而,自从vfork()
被引入以来,
fork()
的实施已经大大改善,最值得注意的是
随着'copy-on-write'的引入,在哪里复制了
通过允许两个进程透明地伪造进程地址空间
在它们中的任何一个修改之前引用相同的物理内存
它。这在很大程度上消除了vfork();
的理由,a
大部分系统现在缺乏原有的功能
完全vfork()
。但是,为了兼容性,可能仍然存在
存在vfork()
来电,只需拨打fork()
即可
试图模仿所有vfork()
语义。
因此,实际使用任何一个是非常不明智的
fork()
和vfork()
之间的差异。的确是
除非你确切知道,否则完全使用vfork()
可能是不明智的
为什么你想要。