3

我正在玩一些 fork/vfork 函数,有些事情让我感到困惑。在史蒂文斯的书中写道:

请注意,在图 8.3 中,我们调用 _exit 而不是 exit。

正如我们在第 7.3 节中所描述的,_exit 不执行任何标准 I/O 缓冲区的刷新。如果我们改为调用 exit,结果是不确定的。根据标准 I/O 库的实现,我们可能会看到输出没有差异,或者我们可能会发现父级 printf 的输出已经消失。如果子调用 exit,实现会刷新标准 I/O 流。如果这是库采取的唯一操作,那么我们将看到与子调用 _exit 时生成的输出没有区别。但是,如果实现还关闭了标准 I/O 流,则表示标准输出的 FILE 对象的内存将被清除。因为child是借用parent的地址空间,所以当parent恢复并调用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 错误。这是为什么?

4

1 回答 1

3

您引用的段落末尾说:

大多数现代的退出实现都不会费心去关闭流。因为进程即将退出,内核会关闭进程中所有打开的文件描述符。在库中关闭它们只会增加开销而没有任何好处。

这很可能是正在发生的事情。您的操作系统实际上并没有关闭流(但它可能会刷新它)。

重要的不是exit这里做什么,而是它的基本概念。孩子正在共享父母的内存和堆栈框架。这意味着孩子可以很容易地改变父母没有预料到的东西,这很容易导致父母在重新开始运行时崩溃或行为不端。的手册页vfork说进程唯一可以做的就是调用exit()exec. 事实上,孩子甚至不应该分配内存或修改任何变量。

要查看其影响,请尝试将vfork调用放在函数内部,让子函数返回或修改其中的一些变量,看看会发生什么。

于 2012-04-05T21:20:14.780 回答