vfork()调用后退出和返回之间的区别

时间:2011-10-06 15:26:15

标签: c posix fork multiprocessing

我有一个程序具有未定义的行为(vfork()使用不当):

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main ( int argc, char *argv[] )
{
    pid_t pid;
    printf("___________befor fork______________.\n");
    if((pid=vfork()) < 0)
        perror("fork");
    else if(pid > 0)
        printf("parent\n");
    else
        printf("child\n");

    printf("pid: %d, ppid: %d\n", getpid(), getppid());

    //exit(0);
    return 0;
}

如果我使用exit(0)函数而不是return - 输出是:

___________befor fork______________.
child
pid: 4370, ppid: 4369
parent
pid: 4369, ppid: 2924

如果我使用return 0 - 我会得到无限输出:

___________befor fork______________.
child
pid: 4455, ppid: 4454
parent
pid: 4454, ppid: 2924
___________befor fork______________.
child
pid: 4456, ppid: 4454
parent
pid: 4454, ppid: 2924
___________befor fork______________.
child
pid: 4457, ppid: 4454
parent
pid: 4454, ppid: 2924
    and so on ...

我知道在return功能之后你不能在孩子身上使用vfork()。 但我不明白为什么父母在return致电后没有结束?

感谢。

4 个答案:

答案 0 :(得分:4)

从子节点中的函数返回是无效的,因为vfork()父节点和子节点共享相同的堆栈并且在子节点中返回将弄乱父节点的堆栈帧。通常调用main()(在start函数中)之后是对exit()或类似的调用,因此对子节点中exit()的调用将覆盖与调用相同的堆栈空间到main()正在使用(并且仍在父母中使用)。因此,当孩子退出时,父母将从vfork()返回,但是堆栈上的返回地址可能会被破坏,因此它可以返回任何地址或做任何事情。

另外,在孩子中,如果你不执行,你应该拨打_exit()而不是exit()exit()将刷新stdio输出缓冲区,但那些相同的缓冲区由父级管理,而_exit()只会结束该过程。

答案 1 :(得分:2)

通过返回子进程,您会导致未定义的行为,因此任何事情都可能发生。

看起来您的父进程工作正常,但子进程不是退出,而是重新启动main函数。

答案 2 :(得分:2)

目前的POSIX标准根本不支持vfork()。 在旧的(1997-ish)POSIX标准中,vfork()的页面说:

  

vfork()函数与fork()具有相同的效果,但如果由vfork()创建的进程修改除{{1}类型的变量之外的任何数据,则行为未定义。用于存储来自pid_t的返回值,或者从调用vfork()的函数返回,或者在成功调用vfork()或其中一个{{1}之前调用任何其他函数函数族。

您的代码未调用_exit()系列函数或exec,因此您调用未定义的行为,并且发生的任何事情都是合法的。

您刚刚证明了使用exec通常不明智的原因。 IMNSHO,它与_exit()在同一个营地;我知道它存在,但我永远不会自愿使用它,我会非常高兴实现:

vfork()

答案 3 :(得分:2)

你可以在kernel.org中看到vfork的定义:http://www.kernel.org/doc/man-pages/online/pages/man2/vfork.2.html。这是一个很好的解释。