Answers:
手册页通常是简洁的参考文档。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几乎无用,因为fork
在vfork
可用的情况下不会进行任何复制。
Linux确实保留了vfork。该fork
系统调用还必须使这一进程的虚拟内存表的副本,即使它不会复制实际内存; vfork
甚至不需要这样做。在大多数应用中,性能改进可忽略不计。
fork
需要创建一个单独的虚拟内存映射,以便后续的写时复制副本仅影响两个进程之一。
的fork()
和vfork()
系统调用是不同的。
的fork()
系统调用产生与单独的存储器两个相同的过程。的vfork()
系统调用,生成共享相同的存储器两个处理。
与vfork()
父母会等待孩子终止。父级从程序共享的变量继承。因此,在调用子代之后,在子代内部修改的所有变量仍将在父代内部进行修改。
欲了解更多信息,请点击这里