1

任何人都可以解释以下代码:

#include<stdio.h>
#include<stdlib.h>
main()
{
  int a=1;
  int pid;
  if((pid = vfork()) == 0)
  {
    printf("This is child . %d\n", getpid() );
    a=2;
  }
  else 
  {
    printf("%d\t%d\n",getpid(),a);
    sleep(1);
  }
}

在上面的代码中,子进程是重复创建的。谁能帮我理解逻辑?

4

2 回答 2

4

阅读手册页vfork。尤其是它告诉你你可以在孩子身上做什么的部分。你不能叫getpid孩子进来。你不能叫printf孩子进来。不允许设置变量a。您不能从子函数中调用的函数返回vfork。你做了所有这些事情,因此代码做了一些意想不到的事情。对你来说不幸的是,意想不到的事情并没有崩溃。

您只能调用:ed child中的_exit一个exec*函数。vfork没有其他的。

系统调用是从非常昂贵vfork的日子开始的优化黑客。fork因此,在子进程调用exec*_exit. 子进程所做的任何内存写入都将覆盖父进程中的内存。调用函数将以父进程不期望的方式覆盖内存。从调用的函数返回vfork肯定会覆盖父级期望完好的状态(如返回地址和保存的堆栈指针)。调用printf将覆盖父级不希望被覆盖的 stdio 缓冲区等。

这可能是为什么在您的情况下,为什么在孩子退出后父母再次调用自己的原因,毕竟计算机是非常确定的。如果您分析调用 main 的 crt 代码、libc 中的各种 atexit 处理程序和其他清理程序,您可能会确切地弄清楚在堆栈上的正确位置写入什么会导致父级混淆并在系统调用返回。反汇编代码并执行它。或者你可以在这个网站上搜索几十个其他问题,vfork并注意到它们都遵循相同的主题:“为什么 vfork 会做一些意想不到的事情当我做某事时,文档告诉我不要做?”。它这样做是因为它是未定义的行为,并且未定义的行为的行为方式是未定义的。在您的情况下,覆盖父级不希望覆盖的内存恰好使父级再次调用自己。在其他情况下,我看到它让 printf 打印了两次。在其他情况下,没有发生任何不好的事情。在其他情况下,程序崩溃了。

于 2014-12-09T09:19:56.030 回答
2

您应该使用 exit() 或 exec 终止子进程。否则孩子的终止状态将不会到达父母。因此,子进程处于僵尸状态。

于 2014-12-09T09:33:39.710 回答