任何人都可以解释以下代码:
#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);
}
}
在上面的代码中,重复创建子进程。有人能帮我理解逻辑吗?
最佳答案
阅读vfork
的手册页。尤其是告诉你在孩子身上可以做什么的部分。不允许在孩子中调用getpid
。不允许在孩子中调用printf
不允许设置变量a
。不允许从子级中调用vfork
的函数返回。你做了所有这些事情,所以代码做了一些意想不到的事情对你来说不幸的是意外的事情并没有发生。
您只能在_exit
ed子项中调用exec*
或其中一个vfork
函数没别的了。vfork
系统调用是从fork
非常昂贵的时候开始的一种优化方法因此,在子进程调用exec*
或_exit
之前,它如何挂起父进程并使用子进程中的父地址空间(这可能是真的,也可能不是真的,具体取决于操作系统)。子进程所做的任何内存写操作都将覆盖父进程中的内存。调用函数将以父进程不期望的方式覆盖内存。从调用vfork
的函数返回肯定会覆盖父级希望保持完整的状态(如返回地址和保存的堆栈指针)。调用printf
将覆盖父级不希望被覆盖的stdio缓冲区,等等。
在你的例子中,家长可能会在孩子退出后再次调用自己,毕竟所有的计算机都是确定性的。如果您分析了调用main的CRT代码,在LBC和其他清理中的各种ATExter处理程序,您可能会确切地知道在SysCurrar返回之后,在堆栈中的正确位置写什么,使父混淆,并返回错误的地方。把代码拆开就可以了或者你可以在这个网站上搜索其他几十个关于vfork
的问题,并注意到它们都遵循相同的主题:“为什么vfork在我做文档告诉我不要做的事情时会做一些意想不到的事情?”。它这样做是因为它是未定义的行为,而未定义的行为的方式是未定义的在您的情况下,父级不希望重写的内存会再次使父级调用本身发生重写在其他情况下,我见过它两次打印printf。在其他情况下,没有发生什么坏事。在其他情况下,程序崩溃了。
关于c - 在vfork子中被重复创建,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27374974/