vfork()调用后退出和返回之间的区别
我有一个程序具有未定义的行为(vfork()使用不当):
#include #include #include int main ( int argc, char *argv[] ) { pid_t pid; printf("___________befor fork______________.\n"); if((pid=vfork()) 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 ...
我知道你不能在vfork()
函数之后使用子vfork()
中的return
。 但我不明白为什么父母在回电后没有结束?
谢谢。
从vfork()
返回是无效的,因为使用vfork()
,父和子共享相同的堆栈,并且在子级中返回将弄乱父级的堆栈帧。 通常调用main()
(在start函数中)之后是对exit()
或类似的调用,因此对子节点中的exit()
调用将覆盖对main()
的调用所使用的相同堆栈空间(并且仍在父母中使用)。 因此当子进程退出时,父vfork()
将从vfork()
返回,但堆栈上的返回地址可能会被破坏,因此它可以返回任何地址或做任何事情。
另外,在孩子中,如果你不执行,你应该调用_exit()
而不是exit()
。 exit()
将刷新stdio输出缓冲区,但那些相同的缓冲区由父级管理,而_exit()
将只结束进程。
通过在子进程中返回,您将导致未定义的行为,因此任何事情都可能发生。
看起来你的父进程工作正常,但子进程,而不是退出,重新启动main
函数。
目前的POSIX标准根本不支持vfork()
。 在旧的(1997-ish)POSIX标准中, vfork()
的页面说:
vfork()
函数与fork()
具有相同的效果,除非如果vfork()
创建的进程修改除了用于存储vfork()
的返回值的pid_t
类型的变量之外的任何数据,则行为未定义,或者从调用vfork()
的函数返回,或者在成功调用_exit()
或exec
函数系列之前调用任何其他函数。
您的代码不会调用exec
系列函数或_exit()
,因此您调用未定义的行为,并且发生的任何事情都是合法的。
您刚刚演示了为什么使用vfork()
通常不合理。 IMNSHO,它与gets()
在同一个阵营; 我知道它存在,但我永远不会自愿使用它,我会非常高兴实现:
pid_t vfork(void) { abort(); } char *gets(char *buffer) { abort(); }
你可以在kernel.org中看到vfork的定义: http ://www.kernel.org/doc/man-pages/online/pages/man2/vfork.2.html。 这是一个很好的解释。