fork()和vfork()有什么区别?


13

我想详细了解fork()和vfork()之间的区别。我无法完全消化手册页。

我还想澄清一下我的一位同事的评论:“ 在当前的Linux中,没有vfork(),即使您调用它,它也会在内部调用fork()。”

Answers:


24

手册页通常是简洁的参考文档。Wikipedia是寻求概念解释的更好的地方。

Fork复制了一个流程:它创建一个与父流程几乎相同的子流程(最明显的区别是新流程具有不同的流程ID)。特别是,fork(从概念上来说)必须复制所有父进程的内存。

由于这相当昂贵,因此发明了vfork来处理不需要复制的常见特殊情况。通常,子进程要做的第一件事是加载新的程序映像,因此发生了以下情况:

if (fork()) {
    # parent process …
} else {
    # child process (with a new copy of the process memory)
    execve("/bin/sh", …);  # discard the process memory
}

execve调用将加载一个新的可执行程序,并用新的可执行文件和新的数据存储器的代码替换进程的代码和数据存储器。因此,由创建的整个内存副本fork一无是处。

因此,vfork呼叫被发明了。它不会复制内存。因此vfork,它很便宜,但是很难使用,因为您必须确保在子进程中不要访问该进程的任何堆栈或堆空间。请注意,甚至读取也是一个问题,因为父进程一直在执行。例如,以下代码是无效的(取决于孩子还是父母首先获得时间片,它可能会起作用,也可能不会起作用):

if (vfork()) {
    # parent process
    cmd = NULL; # modify the only copy of cmd
} else {
    # child process
    execve("/bin/sh", "sh", "-c", cmd, (char*)NULL);  # read the only copy of cmd
}

自从vfork发明以来,已经发明了更好的优化方法。包括Linux在内的大多数现代系统都使用复制的形式,该过程中进程内存中的页面在fork调用时不被复制,而是在父级或子级第一次写入该页面时被复制。也就是说,每个页面都以共享开始,并保持共享,直到任一进程写入该页面为止。写入的过程将获得一个新的物理页面(具有相同的虚拟地址)。写入时复制会使vfork几乎无用,因为forkvfork可用的情况下不会进行任何复制。

Linux确实保留了vfork。该fork系统调用还必须使这一进程的虚拟内存表的副本,即使它不会复制实际内存; vfork甚至不需要这样做。在大多数应用中,性能改进可忽略不计。


1
感谢您给出的出色答案。在执行fork()时,子进程无论如何都将获得新的进程ID及其关联的虚拟空间,那么为什么还要仍然复制该进程的虚拟内存表呢?我在那部分不清楚。
森,

@Sen:fork需要创建一个单独的虚拟内存映射,以便后续的写时复制副本仅影响两个进程之一。
吉尔(Gilles)“所以,别再邪恶了”,

您确定父进程正在运行吗?
qbolec 2014年

2

fork()vfork()系统调用是不同的。

fork()系统调用产生与单独的存储器两个相同的过程。的vfork()系统调用,生成共享相同的存储器两个处理。

vfork()父母会等待孩子终止。父级从程序共享的变量继承。因此,在调用子代之后,在子代内部修改的所有变量仍将在父代内部进行修改。

欲了解更多信息,请点击这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.