vfork() 函数用来创建一个新进程,它具有以下特点:
(1)fork 创建的子进程拷贝父进程的数据段;vfork 创建的子进程共享父进程的数据段。
(2)fork 父子进程执行次序不确定;vfork 保证子进程先执行,子进程调用 exit 或 exec 后父进程被调度。
运行结果(正确):
把上面代码稍作修改,子进程执行体里的 exit 改成 return
运行结果:
程序未退出。why?
如上所述,由 vfork 创建的进程,子进程调用结束调用的是 exit 而不是return。
首先 return 和 exit 的区别:
return 会释放局部变量,并弹栈,回到上级函数执行;exit直接退掉。return 会调用局部对象的析构函数;exit 不会,它没有修改函数栈。
如果在 vfork 中 return 了,那么,这就意味 main() 函数 return 了,因为此时函数栈父子进程共享,所以整个程序的栈就出现问题了。如果在子进程中return,那么基本是下面的过程:
首先子进程的 main() 函数 return了。
而 main() 函数 return 后,通常会调用 exit 或相似的函数。这时,父进程收到子进程exit(),开始从vfork返回,但是父进程的栈都被子进程干掉了,所以接下来的执行出现了不确定性。(注:栈会返回一个诡异一个栈地址,对于某些内核版本的实现,直接报“栈错误”,然而,对于某些内核版本的实现,有可能会再次调用main(),于是进入了一个无限循环的结果,直到 vfork 调用返回 error)
所以,简单来说:上面的例子中,子进程 return 销毁了数据栈,父进程无限的调用 main ,继而无限的执行 vfork ,导致有无限的子进程被创建出来。而子进程 exit 不会破坏数据栈,父进程正常执行。
(3)子进程在父进程的地址空间运行。
fork:
父子进程各有一份a,互不影响
vfork
运行结果:
子进程共享父进程堆栈,子进程修改了a,父进程执行时a的值已经成了101。