任何人都可以解释以下代码:
#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);
}
}
在上面的代码中,重复创建子进程。任何人都可以帮我理解逻辑吗?
答案 0 :(得分:4)
阅读vfork
的手册页。特别是它告诉你孩子可以做什么的部分。您不得在孩子中拨打getpid
。您不得在孩子中拨打printf
。您不能设置变量a
。您不能从孩子中调用vfork
的函数返回。你做了所有这些事情,因此代码做了一些意外的事情。不幸的是,意想不到的事情并没有崩溃。
您只能在_exit
:ed孩子中拨打exec*
或其中一个vfork
个功能。没别了。
vfork
系统调用是从fork
非常昂贵的日子开始的优化黑客攻击。那么在孩子调用exec*
或_exit
之前,暂停父进程并使用子进程中的父进程地址空间(这可能会或可能不是真的,具体取决于操作系统)是做什么的。子进程的任何内存写入都将覆盖父进程中的内存。调用函数将以父进程不期望的方式覆盖内存。从调用vfork
的函数返回肯定会覆盖父期望完整的状态(如返回地址和保存的堆栈指针)。调用printf
将覆盖父母不会被覆盖的stdio缓冲区等。
可能有理由说明为什么在你的情况下,在所有计算机都具有确定性之后,在孩子退出之后父母再次自我调用。如果你分析调用main的crt代码,libc和其他清理中的各种atexit处理程序,你可能会弄清楚在堆栈上的正确位置编写什么会使父进程混淆并返回到错误的位置之后会发生什么。系统调用返回。反汇编代码并进行操作。或者您可以在此网站上搜索有关vfork
的其他几十个问题,并注意它们都遵循相同的主题:&#34;为什么vfork在我做某事时会做出意外的事情文件告诉我不要这样做?&#34;。这样做是因为它的未定义行为和未定义行为的行为方式未定义。在你的情况下,覆盖内存,父母没有预料会被覆盖,这使得父母再次召唤自己。在其他情况下,我已经看到它使printf打印两次。在其他情况下没有发生任何不好在其他情况下,程序崩溃了。
答案 1 :(得分:2)
您应该使用exit()或exec终止子进程。否则孩子 终止状态不会达到父母。所以,子进程处于僵尸状态。