我正在使用fork / vfork函数,有些东西让我感到困惑。在史蒂文斯的书中写道:
请注意,在图8.3中,我们调用_exit而不是exit。
正如我们在7.3节中所述,_exit不执行任何标准I / O缓冲区的刷新。如果我们调用exit,结果是不确定的。 根据标准I / O库的实现,我们可能会看到输出没有差异,或者我们可能会发现父printf的输出已经消失。 如果子调用exit,则实现会刷新标准I / O流。 如果这是库采取的唯一操作,那么如果子进程调用_exit,我们将看到与生成的输出没有区别。 但是,如果实现也关闭标准I / O流,则将清除表示标准输出的FILE对象的内存。 因为孩子正在借用父母的地址空间,所以当父母恢复并调用printf时,不会出现任何输出,printf将返回-1。 请注意,父级的STDOUT_FILENO仍然有效,因为子级获取父级文件描述符数组的副本(请参见图8.2)。 退出的大多数现代实现都不会打扰关闭流。 由于进程即将退出,内核将关闭进程中打开的所有文件描述符。 在库中关闭它们只会增加开销而没有任何好处。
所以我尝试测试我是否可以获得printf错误,在我的vfork手册中有:
刷新并关闭所有打开的stdio(3)流。删除tmpfile(3)创建的文件。
但是当我编译并执行这个程序时:
#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错误。那是为什么?
答案 0 :(得分:3)
你引用的段落的结尾说:
退出的大多数现代实现都不会打扰关闭流。由于进程即将退出,内核将关闭进程中打开的所有文件描述符。在库中关闭它们只会增加开销而没有任何好处。
这很有可能发生了什么。您的操作系统实际上并不关闭流(但它可能会刷新它)。
重要的不是exit
在这里所做的事情,它的基本概念。孩子正在共享父母的记忆和堆叠框架。这意味着孩子可以很容易地改变父母没想到的东西,这很容易导致父母在再次开始跑步时崩溃或行为不端。 vfork
的手册页说明流程唯一可以做的就是调用exit()
或exec
。实际上,孩子甚至不应该分配内存或修改任何变量。
要了解这一点的影响,请尝试将vfork
调用放在函数内部,让子进程返回或修改一些变量,看看会发生什么。