我正在进行一些自我学习的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);
}
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);
}
我们必须比较line a
和line b
的输出。
a部分的输出是:
Value of v is 79525.
Sum is 13.
b部分的输出是:
Value of v is 79517.
Sum is 16.
它出现在a部分中,总和是a
和b
的初始声明的总和,而在b部分中,总和包括子进程中的总和。
我的问题是 - 为什么会发生这种情况?
根据post:
两者之间的基本区别在于新的流程 使用vfork()创建,父进程暂时挂起,并且 子进程可能会借用父进程的地址空间。这个 奇怪的状况持续到孩子处理为止 退出,或调用execve(),此时父进程继续。
父进程的定义暂时中止对我来说没有多大意义。这是否意味着对于1b
,程序在父运行之前等待子进程完成运行(因此子进程变量求和的原因)?
问题陈述还假定"内核维护的父进程的进程ID是2500
,并且新进程是在创建子进程之前由操作系统创建的。 #34;
根据这个定义,两个程序的v
值是多少?
答案 0 :(得分:5)
父进程暂时中止
基本上,在孩子调用_exit
或其中一个exec
函数之前,父进程不会运行。在您的示例中,这意味着子项将运行,因此在父项运行并执行打印之前执行求和。
至于:
我的问题是 - 为什么会发生这种情况?
首先,你的b部分有未定义的行为,因为你违反了vfork
语义。程序的未定义行为意味着程序不会以可预测的方式运行。有关更多详细信息,请参阅this SO post on undefined behavior(它包含一些C ++,但大多数想法都相同)。来自POSIX specs on vfork
:
vfork()函数与fork(2)具有相同的效果,除了 如果由vfork()创建的进程也未定义行为 修改除用于存储的pid_t类型的变量之外的任何数据 来自vfork()的返回值,或者从其中返回的函数返回 vfork()被调用,或者在成功之前调用任何其他函数 调用_exit(2)或exec(3)函数族之一。
所以你的b部分真的可以做任何事情。但是,您可能会看到b部分的输出有些一致。这是因为当您使用vfork
时,您不会创建新的地址空间。相反,子进程基本上“借用”父进程的地址空间,通常是为了调用其中一个exec
函数并创建一个新的程序映像。而是在您的部分b中使用父地址空间。基本上,孩子打电话exit
后(因为它应该调用_exit
也是无效的)a
最有可能等于10而b
最有可能等于6 <强>在父母中。因此,总和为16,如b部分所示。我说很可能是因为如前所述,这个程序有未定义的行为。
对于使用fork
的部分a,子项获得自己的地址空间,并且在父项中看不到其修改,因此打印的值为13(5 + 8)。
最后关于v
的价值,这似乎只是一个问题,即使其显示的输出有意义。 v
的值可以是vfork
或fork
返回的任何有效值,并且不必限制为2500.