vfork函数的调用序列和返回值与fork相同,但两者的语义不同。
vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。vfork与fork都创建一个子进程,但它不将父进程的地址空间复制到子进程中,因为子进程会立即调用exec,于是不会存访问该地址空间。相反,在子进程调用exec或exit之前,它在父进程的空间中运行,也就是说会更改父进程的数据段、栈和堆。vfork和fork另一区别在于:vfork保证子进程先运行,在它调用exec之后父进程才可能被调度运行。
下面是vfork的使用程序:
[cpp] view plaincopy执行及输出结果如下所示:
chen123@ubuntu:~/user/apue.2e$./a.out
before vfork
pid = 2984, glob= 7, var = 89
可见子进程直接改变了父进程的变量值,因为子进程在父进程的地址空间中运行。
这里子进程调用_exit是因为_exit并不执行标准I/O缓冲的冲洗操作。如果调用exit,该程序结果不确定,依赖于标准I/O库的实现。因为exit有可能关闭标准I/O流,那么会使父进程不产生任何输出。
进程有5中正常终止方式,3中异常终止方式。(见上一篇文章)。
对于任意一种终止情形,我们都希望终止进程能够统治父进程它是如何终止的。对于三个终止函数(exit、_exit和_Exit),实现这一点的方法是,将其退出状态作为参数传送给函数。在异常终止情况下,内核产生一个指示其异常终止原因的终止状态。在任意一种情况下,该终止状态的父进程都能使用wait或waitpid函数取得其终止状态。
在调用_exit时,内核将进程的退出状态转换成终止状态。
对于父进程已经终止的所有进程,他们的父进程都改变为init进程。我们称这些进程有Init领养。一个init的子进程(包括领养进程)终止时,init会调用一个wait函数取得其终止状态。
对于一个已经终止、但其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占有的资源)的进程被称为僵尸进程。子进程终止时,虽然不在运行,但它仍然存在与系统中,进程表中代表子进程的表项不会立刻被释放,因为它的退出码还需要保存在进程表项中以备父进程今后的wait调用使用,也就是说终止子进程与父进程之间的关联还会保持,直到父进程也正常的终止或父进程调用wait才告结束。