下面的代码永远不会结束。 这是为什么?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE 5
int nums[SIZE] = {0, 1, 2, 3, 4};
int main()
{
int i;
pid_t pid;
pid = vfork();
if(pid == 0){ /* Child process */
for(i = 0; i < SIZE; i++){
nums[i] *= -i;
printf(”CHILD: %d “, nums[i]); /* LINE X */
}
}
else if (pid > 0){ /* Parent process */
wait(NULL);
for(i = 0; i < SIZE; i++)
printf(”PARENT: %d “, nums[i]); /* LINE Y */
}
return 0;
}
更新:
该代码只是为了说明一些我有一个关于在混乱中vfork()
这似乎是,当我使用vfork()
子进程不会复制父母的地址空间。 取而代之的是,这股地址空间。 在这种情况下,我预计NUMS阵列得到由两种处理的更新,我的问题是在什么样的顺序? 操作系统两者之间如何同步?
至于为什么代码永远不会结束,可能是因为我没有任何_exit()
或exec()
语句明确了退出。 我对吗?
UPDATE2:
我刚才读: 叉()和vfork()系统调用56之间的差异? 我认为这篇文章可以帮助我与我的第一个困惑。
来自的vfork()系统调用的子进程的父进程的地址空间执行(这可以覆盖父的数据和堆栈),它暂停父进程,直到子进程退出。
不要使用vfork
。 这是你可以得到最简单的建议。 那唯一vfork
为您提供了将暂停家长直到孩子要么调用exec*
或_exit
。 有关共享地址空间的部分是不正确,有些操作系统做到这一点,其他不选择,因为它是非常不安全的,并已造成了严重的错误。
上次我看了应用程序如何使用vfork
现实中的绝对多数没有错。 它是如此糟糕,我扔掉了6个字符的变化是启用的地址空间共享的操作系统我当时工作的。 几乎每个人都谁使用vfork
至少出现内存泄漏如果不是更糟。
如果你真的想用vfork
,不这样做除了立即拨打任何_exit
或execve
它的子进程返回后。 还有什么你正在进入不确定的领土。 我真的是“什么”。 你开始解析你的字符串,使论据你exec调用,你都会有很大保证的东西会触动一些它不该碰。 我也意味着execve
,而不是从exec类的一些其他功能。 很多的libc在那里做的事情execvp
, execl
, execle
,等那是在一个不安全vfork
上下文。
什么是具体发生在你例子:
如果您的操作系统共享地址空间中的孩子从main返回意味着你的环境清理的东西了(平标准输出,因为你叫printf的,这是由printf和这样的事情分配的内存)。 这意味着,还有其他的函数调用,将覆盖栈帧父被卡住英寸vfork
在父返回到已被覆盖,任何事情都有可能发生堆栈帧返回,它甚至可能没有在堆栈上的返回地址返回了。 您首先通过调用printf的进入未定义行为的国家,然后从主回把你带到了未定义行为的大陆,并从主您前往未定义行为星球回归后作出清理运行。
从引用vfork(2)
手册页:
所述的vfork()函数具有作为叉),所不同的是,如果()或者通过vfork的创建的流程修改比用于存储从vfork的返回值的类型将为pid_t的变量之外的任何数据的行为是未定义相同的效果(,(),或从函数返回其中的vfork()被调用,或者调用任何其它函数之前成功调用_exit()或函数的EXEC家族的一员。
你做一大堆的那些东西,所以你不应该期望它的工作。 我觉得这里真正的问题是:为什么你使用vfork()
而不是fork()
?
从官方的规格 :
如果()由vfork的创建的流程修改比用于存储从vfork的返回值的类型将为pid_t的变量之外的任何数据(行为是未定义),
在你的程序修改比其他数据pid
变量,这意味着该行为是不确定的。
您也可以致电_exit
来结束进程,或致电之一exec
系列函数。
儿童必须_exit
而不是返回main
。 如果孩子从返回main
,那么栈帧不父,当它从返回存在vfork
。
只需调用_exit而不是调用返回或插入_exit(0)到“子进程”的最后一行。 返回0调用退出(0),而接近标准输出,另一个的printf如下这样的情况下,程序崩溃。