C语言 fork() 和 vfork() 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4259629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between fork() and vfork()?
提问by user507401
回答by Blagovest Buyukliev
The intent of vforkwas to eliminate the overhead of copying the whole process image if you only want to do an exec*in the child. Because exec*replaces the whole image of the child process, there is no point in copying the image of the parent.
的目的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 */
}
For other kinds of uses, vforkis dangerous and unpredictable.
对于其他种类的用途,vfork是危险的和不可预测的。
With most current kernels, however, including Linux, the primary benefit of vforkhas disappeared because of the way forkis implemented. Rather than copying the whole image when forkis executed, copy-on-write techniques are used.
然而,对于包括 Linux 在内的大多数当前内核,vfork由于fork实现方式的原因,它的主要优势已经消失。不是在fork执行时复制整个图像,而是使用写时复制技术。
回答by dcoz
As already stated, the vforkman page is clear about the differences.
This topicgives a good description of fork, vfork, cloneand exec.
如前所述,vfork手册页清楚地说明了差异。这个话题给出了一个很好的说明fork,vfork,clone和exec。
Below are some often overlooked differences between forkand vforkI experienced on some Linux 2.6.3x embedded systems I worked with.
以下是我在使用的一些 Linux 2.6.3x 嵌入式系统上fork与vfork我所经历的一些经常被忽视的差异。
Even with copy-on-write techniques, forkfails if you don't have enough memory to duplicate the memory used by the parent process. For example, if the parent process uses 2 GB of resident memory (ie, memory that is used and not just allocated), forkfails if you have less than 2 GB of free memory left. That's frustrating when you just want to execa simple program and therefore will never need that huge parent address space!
即使使用写时复制技术,fork如果您没有足够的内存来复制父进程使用的内存,也会失败。例如,如果父进程使用 2 GB 的常驻内存(即,已使用的而不是刚刚分配的内存),fork如果剩余的可用内存少于 2 GB,则会失败。当您只想要exec一个简单的程序并且因此永远不需要巨大的父地址空间时,这令人沮丧!
vforkdoesn't have this memory issue, as it doesn't duplicate the parent address space. The child process acts more like a thread in which you are able to call exec*or _exitwithout hurting your parent process.
vfork没有这个内存问题,因为它不复制父地址空间。子进程更像是一个线程,您可以在其中调用exec*或_exit不伤害父进程。
Because memory page tables are not duplicated, vforkis much faster than forkand vfork's execution time is not affected by the amount of memory the parent process uses, as pointed out here: http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/
因为内存页表不是重复的,vfork所以比fork和vfork的执行时间快得多,它的执行时间不受父进程使用的内存量的影响,正如这里所指出的:http: //blog.famzah.net/2009/11/20 /fork-gets-slower-as-parent-process-use-more-memory/
In situations where performance is critical and/or memory limited, vfork+ exec*can therefore be a good alternative to fork+ exec*. The problem is that it is less safe and the man page says vforkis likely to become deprecated in the future.
在性能至关重要和/或内存有限的情况下,vfork+exec*因此可以是fork+ 的一个很好的替代品exec*。问题是它不太安全,手册页说vfork将来可能会被弃用。
A safer and more portable solution may be to look at the posix_spawnfunction, which is higher level and offers more options. It safely uses vforkwhen possible, depending on the options you pass it. I have been able to use posix_spawnsuccessfully and overcome that annoying "double memory checking issue" that fork+ execwas giving me.
一个更安全、更便携的解决方案可能是看posix_spawn功能,它的级别更高,提供更多的选择。它vfork在可能的情况下安全使用,具体取决于您传递的选项。我已经能够posix_spawn成功使用并克服fork+exec给我带来的烦人的“双重内存检查问题” 。
A really good page on this topic, with links to some posix_spawnexamples.
回答by SiegeX
From my man page
从我的手册页
(From POSIX.1) The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions.
vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, including the stack. The child must not return from the current function or call exit(3), but may call _exit(2).
(来自 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)。
回答by cpp-coder
Some systems have a system call vfork(), which was originally designed as a lower-overhead version of fork(). Since fork() involved copying the entire address space of the process, and was therefore quite expensive, the vfork() function was introduced (in 3.0BSD).
一些系统有一个系统调用 vfork(),它最初被设计为 fork() 的低开销版本。由于 fork() 涉及复制进程的整个地址空间,因此非常昂贵,因此引入了 vfork() 函数(在 3.0BSD 中)。
However, since vfork() was introduced, the implementation of fork() has improved drastically, most notably with the introduction of `copy-on-write', where the copying of the process address space is transparently faked by allowing both processes to refer to the same physical memory until either of them modify it. This largely removes the justification for vfork(); indeed, a large proportion of systems now lack the original functionality of vfork() completely. For compatibility, though, there may still be a vfork() call present, that simply calls fork() without attempting to emulate all of the vfork() semantics.
然而,自从引入 vfork() 后,fork() 的实现得到了极大的改进,最显着的是引入了“copy-on-write”,其中通过允许两个进程引用来透明地伪造进程地址空间的复制到相同的物理内存,直到他们中的任何一个修改它。这在很大程度上消除了 vfork() 的理由;事实上,现在很大一部分系统完全缺乏 vfork() 的原始功能。但是,为了兼容性,可能仍然存在 vfork() 调用,它只是调用 fork() 而不尝试模拟所有 vfork() 语义。
As a result, it is very unwise to actually make use of any of the differences between fork() and vfork(). Indeed, it is probably unwise to use vfork() at all, unless you know exactly why you want to.
因此,实际上利用 fork() 和 vfork() 之间的任何差异是非常不明智的。事实上,使用 vfork() 可能是不明智的,除非您确切地知道为什么要这样做。
The basic difference between the two is that when a new process is created with vfork(), the parent process is temporarily suspended, and the child process might borrow the parent's address space. This strange state of affairs continues until the child process either exits, or calls execve(), at which point the parent process continues.
两者的基本区别在于,当使用 vfork() 创建新进程时,父进程会被暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状态一直持续到子进程退出或调用 execve(),此时父进程继续。
This means that the child process of a vfork() must be careful to avoid unexpectedly modifying variables of the parent process. In particular, the child process must not return from the function containing the vfork() call, and it must not call exit() (if it needs to exit, it should use _exit(); actually, this is also true for the child of a normal fork()).
这意味着 vfork() 的子进程必须小心避免意外修改父进程的变量。特别是子进程一定不能从包含vfork()调用的函数中返回,也不能调用exit()(如果需要退出,应该使用_exit();实际上,对于子进程也是如此一个普通的 fork())。
回答by Rajesh Pal
The basic difference between the two is that when a new process is created with vfork(), the parent process is temporarily suspended, and the child process might borrow the parent's address space. This strange state of affairs continues until the child process either exits, or calls execve(), at which point the parent process continues.
两者的基本区别在于,在创建新进程时vfork(),父进程会被暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状态一直持续到子进程退出或调用execve(),此时父进程继续。
This means that the child process of a vfork()must be careful to
avoid unexpectedly modifying variables of the parent process. In
particular, the child process must not return from the function
containing the vfork()call, and it must not call
exit()(if it needs to exit, it should use _exit();actually, this is also true for the child of a normal fork()).
这意味着 a 的子进程vfork()必须小心避免意外修改父进程的变量。特别是子进程一定不能从包含vfork()调用的函数返回,也不能调用
exit()(如果需要退出,应该_exit();实际使用,正常的子进程也是如此fork())。
However, since vfork()was introduced, the
implementation of fork()has improved drastically, most notably
with the introduction of 'copy-on-write', where the copying of the
process address space is transparently faked by allowing both processes
to refer to the same physical memory until either of them modify
it.This largely removes the justification for vfork();indeed, a
large proportion of systems now lack the original functionality of
vfork()completely. For compatibility, though, there may still be
a vfork()call present, that simply calls fork()without
attempting to emulate all of the vfork()semantics.
然而,自从vfork()被引入以来,它的实现fork()已经有了巨大的改进,最显着的是“写时复制”的引入,其中通过允许两个进程引用相同的物理内存来透明地伪造进程地址空间的复制,直到他们中的任何一个修改它。这在很大程度上消除了vfork();确实的理由,现在很大一部分系统vfork()完全缺乏原始功能
。但是,为了兼容性,可能仍然存在一个vfork()调用,它只是调用fork()而不尝试模拟所有vfork()语义。
As a result, it is very unwise to actually make use of any of the
differences between fork()and vfork(). Indeed, it is
probably unwise to use vfork()at all, unless you know exactly
why you want to.
其结果是,这是非常不明智的实际使用任何的之间的差异fork()和vfork()。事实上,使用它可能是不明智的vfork(),除非您确切地知道为什么要使用。
回答by Vishal
On some systems, vfork() is the same as fork(). The vfork() function differs from fork() only in that the child process can share code and data with the calling process (parent process).
在某些系统上,vfork() 与 fork() 相同。vfork() 函数与 fork() 的不同之处仅在于子进程可以与调用进程(父进程)共享代码和数据。

