Answers:
正如前面看到的,vfork
不允许子进程来访问父进程的内存。exit
是C库函数(这就是为什么通常将其编写为exit(3)
)的原因。它执行各种清理任务,例如刷新和关闭C流(通过中声明的函数打开文件stdio.h
)以及执行向用户注册的用户指定函数atexit
。所有这些任务都涉及读取和写入过程存储器。
_exit
退出而不进行清理。它是直接的系统调用(这就是为什么将其编写为_exit(2)
),通常是通过将系统调用号放在处理器寄存器中并执行特定的处理器指令(分支到系统调用处理程序)来实现的。这不需要访问进程内存,因此在执行操作之后是安全的vfork
。
之后fork
,就没有这种限制:父进程和子进程现在是完全自治的。
init
也由内核派生)。
exit
做额外的清理工作,例如调用由其注册的函数,atexit
因此它访问复制部分之外的数据。_exit
直接执行系统调用,而无需清除内核内的任何清理。
子调用_exit()可以避免在子进程退出时刷新stdio(或其他)缓冲区。由于子进程构成了父进程的精确副本,因此子进程仍具有父进程“ stdout”或“ stderr”(<stdio.h>中的缓冲区)中的内容。当父进程中的缓冲区已满并被刷新时,您可以(并且会在不适当的时间)通过调用exit()获得双倍输出,其中一个来自子进程的atexit处理程序,另一个来自父进程。
我意识到上面的答案集中在stdio.h细节上,但是这个想法可能会延续到其他缓冲的I / O,正如上面的答案之一所示。
exit()
:-执行一些清理任务,例如关闭I / O流和许多流,然后返回内核。
_exit()
:-直接进入内核(不执行任何清理任务)。
fork()
:父级和子级都有不同的文件表,因此,子级所做的更改不会影响父级的环境参数,反之亦然。
vfork()
:父级和子级都使用相同的文件表,因此子级所做的更改会影响父级的环境参数。例如,一些变量var=10
,现在var++
由child运行,然后由parent运行,您也可以var++
在parent输出中看到的效果。
就像我说的那样,如果使用exit()
,vfork()
则所有I / O已经关闭。因此,即使parent运行正常,您也无法获得正确的输出,因为所有变量均已清空,所有流均已关闭。