#include<stdio.h>
#include<sys/types.h>
int main()
{
pid_t pid;
if((pid=vfork())<0)
{
perror("FORK ERROR");
exit(1);
}
if(pid==0)
{
printf("[CHILD] child id : %d\n" , pid);
_exit(1);
}
else
{
printf("[PARENT] process id : %d\n" , pid);
exit(1);
}
}
上述程序使用vfork创建进程。 因此,父母和孩子之间共享地址空间。 这意味着只有一个pid变量副本。 但是当我在子元素中打印pid变量时,它给出了0.父元素中的相同pid变量给出了子元素的进程id。 如果只有一个pid变量副本,这怎么可能。
答案 0 :(得分:3)
假设您有一个真正的vfork
,它不仅仅是根据fork
实现的,那么该程序会调用严重的未定义行为。子进程中的printf
将修改父进程的地址空间中的相同FILE
对象(stdout
),可能使其处于对父进程无效的状态。在实践中它可能会起作用,但如果确实如此,这是实施细节的结果,你不能依靠不改变。 vfork
_exit
之后唯一可以安全执行的操作是exec
和printf
系列函数。
至于 如何工作(以vfork
问题为模),vfork
暂停父进程直到子进程终止,所以当{{1}}返回时父,孩子已经退出,新的返回值可以存储在旧孩子存放的同一位置。
答案 1 :(得分:0)
父节点从子节点后面的vfork()返回,所以pid被“正确”值覆盖。
在内核源代码树中,kernel / fork.c
在函数do_fork()
中 do_fork()
{
......
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
get_task_struct(p);
}
wake_up_new_task(p);
/* forking complete and child started to run, tell ptracer */
if (unlikely(trace))
ptrace_event(trace, nr);
if (clone_flags & CLONE_VFORK) {
if (!wait_for_vfork_done(p, &vfork))
ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
.....
return nr; // pid of the child process.
}
您可以看到对 wait_for_vfork_done 的调用。 所以父母在这里等待vfork返回。 一旦孩子退出,父母就会从这里恢复。 孩子的pid从这里退回。 所以相同的pid变量在父级和子级中给出不同的值。