【问题标题】:vfork return values to parent and childvfork 将值返回给父母和孩子
【发布时间】:2012-08-29 14:22:34
【问题描述】:
#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 变量只有一个副本,这怎么可能。

【问题讨论】:

  • 只有一个 pid 副本存在。在孩子和父母中打印pid的地址是相同的。同样根据 vfork 文档,父子节点共享相同的地址空间。
  • 我已经删除了我的答案;重复的问题解释得更好。

标签: c linux-kernel fork system-calls


【解决方案1】:

假设你有一个真实的vfork,它不只是根据fork 实现的,这个程序会调用严重的未定义行为。子进程中的printf 将修改父进程地址空间中的相同FILE 对象(stdout),可能使其处于对父进程无效的状态。在实践中它可能会起作用,但如果确实如此,那是实现细节的结果,你不能依靠不改变。在vfork 之后可以安全执行的唯一操作是_exitexec 系列函数。

至于如何它的工作原理(以printf 为模),vfork 暂停父进程直到子进程终止,所以当vfork 在父进程中返回时,子进程已经退出并且新的返回值能够存储在旧返回值存储在子级中的相同位置。

【讨论】:

  • 我已经为孩子使用了 _exit(1)。 if(pid==0) { printf("[CHILD] 孩子 id : %d\n" , pid); _exit(1);这绝对没问题。仅当您使用 exit(1) 时,它才会关闭标准输出并导致未定义的错误/
  • 调用printf也是个问题。这会修改 stdout,稍后将在父级中使用。 vfork 不在任何现代标准中,但原始定义(在 SVID 中,如果我没记错的话)指定在 vfork 之后调用除 _exitexec 之外的任何内容都是 UB。
【解决方案2】:

父级在子级之后从 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 变量在父子节点中给出不同的值。

【讨论】:

    猜你喜欢
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多