我正在做一些自我学习的C练习,并遇到了以下问题:
第一部分:
int main(int argc, char **argv) {
int a = 5, b = 8;
int v;
v = fork();
if(v == 0) {
// 10
a = a + 5;
// 10
b = b + 2;
exit(0);
}
// Parent code
wait(NULL);
printf("Value of v is %d.\n", v); // line a
printf("Sum is %d.\n", a + b); // line b
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
b部分:
int main(int argc, char **argv) {
int a = 5, b = 8;
int v;
v = vfork();
if(v == 0) {
// a = 10
a = a + 5;
// b = 6
b = b - 2;
exit(0);
}
// Parent code
wait(NULL);
printf("Value of v is %d.\n", v); // line a
printf("Sum is %d.\n", a + b); // line b
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
我们要的输出比较line a和line b.
a部分的输出是:
Value of v is 79525.
Sum is 13.
Run Code Online (Sandbox Code Playgroud)
b部分的输出是:
Value of v is 79517.
Sum is 16.
Run Code Online (Sandbox Code Playgroud)
它出现在部分a中,总和是初始声明a和b的总和,而在部分b中,总和包括子进程中的总和.
我的问题是 - 为什么会发生这种情况?
根据这篇文章:
两者之间的基本区别在于,当使用vfork()创建新进程时,父进程将暂时挂起,子进程可能会借用父进程的地址空间.这种奇怪的状态一直持续到子进程退出或调用execve(),此时父进程继续.
父进程的定义暂时中止对我来说没有多大意义.这是否意味着,1b在父运行之前,程序会等到子进程完成运行(因此子进程变量求和的原因)?
问题陈述还假定"内核维护的父进程的进程ID是2500,并且在创建子进程之前由操作系统创建新进程".
根据这个定义,v两个计划的价值是什么?
父进程暂时中止
基本上,父进程在子进程调用其中_exit一个exec函数或其中一个函数之前不会运行.在您的示例中,这意味着子项将运行,因此在父项运行并执行打印之前执行求和.
至于:
我的问题是 - 为什么会发生这种情况?
首先,你的b部分有未定义的行为,因为你违反了vfork语义.程序的未定义行为意味着程序不会以可预测的方式运行.有关更多详细信息,请参阅有关未定义行为的SO帖子(它包含一些C++,但大多数想法都相同).从POSIX规范vfork:
vfork()函数与fork(2)具有相同的效果,除非如果vfork()创建的进程修改除了用于存储vfork()的返回值的pid_t类型的变量之外的任何数据,则行为未定义. ,或从调用vfork()的函数返回,或在成功调用_exit(2)或exec(3)函数系列之前调用任何其他函数.
所以你的b部分真的可以做任何事情.但是,您可能会看到b部分的输出有些一致.这是因为当您使用时,vfork您不会创建新的地址空间.相反,子进程基本上"借用"父进程的地址空间,通常意图是它将调用其中一个exec函数并创建一个新的程序映像.而是在您的部分b中使用父地址空间.基本上,在孩子打电话后exit(因为它应该打电话也是无效的_exit),a很可能会等于10并且b很可能在父母中等于6 .因此,总和为16,如b部分所示.我说的很可能是因为如前所述,这个程序有不确定的行为.
对于使用where的部分fork,子项获得自己的地址空间,并且在父项中看不到其修改,因此打印的值为13(5 + 8).
最后关于价值v,这似乎只是一个问题,说明使其显示的输出有意义.值v可以是由vfork或返回的任何有效值,fork并且不必限制为2500.
| 归档时间: |
|
| 查看次数: |
3932 次 |
| 最近记录: |