我用fork / vfork函数玩了一下,有些东西让我感到困惑。 在史蒂文斯的书中写道:
请注意,在图8.3中,我们称之为_exit而不是exit。
正如我们在7.3节中所描述的,_exit不会执行任何标准I / O缓冲区的刷新。 如果我们叫退出,结果是不确定的。 根据标准I / O库的实现,我们可能会看到输出中没有任何区别,或者我们可能会发现父级printf的输出已经消失。 如果subprocess调用exit,则执行刷新标准I / Ostream。 如果这是图书馆采取的唯一行动,那么如果孩子名为_exit,我们将看到没有区别。 如果实现也closures标准I / Ostream,则表示标准输出的FILE对象的内存将被清除。 由于孩子正在借用父母的地址空间,当父母继续并调用printf时,不会显示输出,printf将返回-1。 请注意,父级的STDOUT_FILENO仍然有效,因为子级获得了父级文件描述符数组的副本(请参阅图8.2)。 大多数现代实现的退出不会麻烦closuresstream。 由于进程即将退出,内核将closures进程中打开的所有文件描述符。 在图书馆closures它们只是增加开销而没有任何好处。
所以我试图testing,如果我可以得到printf错误,在我的vfork手册有:
所有打开的stdio(3)stream都被刷新并closures。 由tmpfile(3)创build的文件被删除。
但是当我编译和执行这个程序时:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> int main() { int s; pid_t ret; if (vfork() == 0) { //abort(); exit(6); } else { ret=wait(&s); printf("termination status to %d\n",s); if (WIFEXITED(s)) printf("normalnie, status to %d\n",WEXITSTATUS(s)); } return 0; }
一切工作正常,我没有得到任何printf错误。 这是为什么?
你引用段落的末尾说:
大多数现代实现的退出不会麻烦关闭流。 由于进程即将退出,内核将关闭进程中打开的所有文件描述符。 在图书馆关闭它们只是增加开销而没有任何好处。
这很可能是发生了什么事情。 你的操作系统并没有真正的关闭流(但是可能会刷新它)。
重要的不是exit
在这里,它的基本概念。 孩子正在分享父母的记忆和堆栈框架。 这意味着孩子可以很容易地改变父母没有想到的事情,这很容易导致父母在再次开始跑步时崩溃或不正常。 vfork
的手册页说,进程可以做的唯一事情就是调用exit()
或exec
。 事实上,孩子甚至不应该分配内存或修改任何变量。
为了看到这个影响,可以尝试把vfork
调用放在一个函数中,并让子进程返回或修改一些变量,看看会发生什么。