首页 > 代码库 > 进程终止和exit函数

进程终止和exit函数

内核要执行一个应用程序,唯一的途径是通过系统调用,exec函数,exec又会调用启动程序,启动程序(通常是汇编语言)以类似下面的方式调用main函数:
void exit(main(argc, argv));

那么在main函数末尾使用exit(0)和使用return 0是等价的。这里有三个正常终止程序的函数:
void exit(int status);     // 先执行一些清理操作,然后进入内核
void _Exit(int status);    // 立即进入内核,可在所有函数中调用
void _exit(int status);    // 立即进入内核,可在所有函数中调用

exit函数一般做三类事情:
  • 执行由atexit函数登记的各终止处理程序
  • 总是执行一个标准IO库的清理关闭操作:为所有打开流调用fclose函数
  • 调用_exit或_Exit函数返回内核
注意最后一步,exit最终还是要调用_exit或_Exit回到内核。进程有5种正常终止方式和3种异常终止方式(P178),不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有开打描述符,释放它所使用的存储器等。

注意到上面三个函数的参数status,这是进程退出时的退出状态,内核将退出状态转换成终止状态。该终止状态能够由该进程的父进程通过wait或waitpid函数捕获,也就是说父进程能够获得子进程退出时的终止状态。

根据上面的描述,有几个问题需要考虑:
  • 父进程在子进程之前终止,会发生什么?这种情况下,它们的父进程会改变为init进程,称由init进程领养。
  • 子进程在父进程之前终止,内核为终止子进程保存的信息如何给父进程?在这种情况下,父进程调用wait或waitpid可以得到这些信息。如果父进程没有进行这样的调用,则子进程占用的资源不会完全释放,这时该子进程称为僵死进程
  • 由init领养的进程终止时会发生什么?init被编写成无论何时,只要有子进程终止,它都会调用wait函数获得其终止状态。所以init的子进程不可能成为僵死进程。

参考:
《unix环境高级编程》 P147-P151、P178.