fork()
和vfork()
什么区别? vfork()
是否像fork()
那样返回?
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在内的大多数当前的内核来说,由于fork
的实现方式, vfork
的主要优点已经消失。 当执行fork
时,不是复制整个图像,而是使用写入时复制技术。
如前所述, vfork
手册页清楚地说明了这些差异。 本主题对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/二十零分之十一/叉得到-慢作为父进程使用-更多存储器/
在性能严重和/或内存有限的情况下, vfork
+ exec*
因此可以成为fork
+ exec*
一个很好的选择。 问题在于它不太安全,手册页说vfork
很可能在未来被弃用。
一个更安全和更便携的解决方案可能是看posix_spawn
功能,这是更高的水平,并提供更多的选择。 它可以安全地使用vfork
,这取决于你传递的选项。 我已经能够成功地使用posix_spawn
并克服fork
+ exec
给我的恼人的“双重内存检查问题”。
关于这个主题的一个非常好的页面,带有一些posix_spawn
示例的链接。
从我的手册页
(从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)。
有些系统有一个系统调用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())。
请参考这里和从维基百科 –
在一些系统上,vfork()和fork()是一样的。 vfork()函数与fork()的不同之处在于,子进程可以与调用进程(父进程)共享代码和数据。
两者之间的基本区别在于,当使用vfork()
创建新进程时,父进程暂时挂起,并且子进程可能借用父进程的地址空间。 这种奇怪的状态继续下去,直到子进程退出,或调用execve()
,在这一点父进程继续。
这意味着vfork()
的子进程必须小心,以避免意外地修改父进程的变量。 特别是,子进程不能从包含vfork()
调用的函数返回,并且不能调用exit()
(如果需要退出,应该使用_exit();
实际上,对于孩子来说也是如此一个普通的fork()
)。
但是,由于引入了vfork()
, fork()
的实现得到了极大的改善,最引人注目的是引入了“copy-on-write”, 通过允许这两个进程参照进程地址空间的复制是透明伪造的到相同的物理内存,直到其中任何一个修改它。 这在很大程度上消除了vfork();
的理由vfork();
实际上,大部分系统现在完全没有vfork()
的原始功能。 尽管为了兼容性,仍然可能存在一个vfork()
调用,它只是简单地调用fork()
而不尝试模拟所有的vfork()
语义。
因此,实际上使用fork()
和vfork()
之间的任何区别是非常不明智的。 的确,使用vfork()
根本不明智,除非你确切地知道你为什么vfork()
。