我想详细了解 fork() 和 vfork() 之间的区别。我无法完全理解手册页。
我还想澄清我的一位同事的评论“目前的Linux中,没有vfork(),即使你调用它,它内部也会调用fork()”。
答案1
手册页通常是简洁的参考文档。维基百科是寻求概念解释的更好地方。
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
甚至不需要这样做。在大多数应用中,性能改进可以忽略不计。
答案2
fork()
和系统vfork()
调用是不同的。
系统fork()
调用生成两个具有独立内存的相同进程。系统vfork()
调用生成两个共享同一内存的进程。
父进程vfork()
将等待子进程终止。父级继承了程序共享的变量。因此,在子进程被调用之后,子进程内部修改的所有变量仍然会在父进程内部被修改。
欲了解更多信息,请点击这里