exit() 和 _exit()函数详解

exit() 和 _exit()函数详解

exit() 就是让程序退出,传入的参数是程序退出时的状态码,0 表示正常退出,其他表示非正常退出。标准中有:EXIT_SUCCESSEXIT_FAILURE 两个宏。

作为系统调用,_exitexit 是基本一样的。在内核中,有如下的定义

1
#define __NR__exit  __NR_exit

以下再说几点区别:

  • exit() 函数定义在 stdlib.h 中,而 _exit() 定义在 unistd.h
  • _exit() 函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上做了一些包装,在执行退出前加了若干道工序。
  • 两者最大的区别在于 exit()函数在执行前要先检查文件的打开情况,把文件缓冲区中的内容写回文件,就是“清理 IO 缓冲”

1. exit() 在结束调用它的进程之前,要进行如下步骤

  1. 调用 atexit() 注册的函数,按 atexit 注册时相反的顺序调用所有由它注册的函数,这使得我们可以指定在程序终止时执行自己的清理动作。例如,保存程序状态信息于某个文件,解开对共享数据库的锁等
  2. cleanup() 关闭所有打开的流,这将导致写所有被缓冲的输出到文件;删除用 tmpFile 函数建立的所有临时文件
  3. 最后调用 _exit() 函数终止进程

2. _exit() 做如下事情

  1. 关闭属于该进程的任何打开的文件描述符
  2. 让该进程的所有子进程都由 init(1号进程)继承
  3. 向该进程的父进程发送 SIGCHLD 信号

3. 注意

  • 对于有缓冲的 IO,比如 printf、fopen、fread、fwrite 等等,如果调用 _exit()函数直接将进程关闭,可能会使缓冲区中的数据丢失。如果想要保证数据的完整性,就一定要使用 exit() 函数
  • 相同点,不管进程是如何终止的,内核都会关闭进程打开的所有文件描述符,释放进程使用的内存。

在一个 fork 的子进程分支中,使用 _exit 函数而不是 exit 函数?

如果在 fork 创建的子进程分支中使用 exit 函数,会导致标准输入输出的缓冲区被清空两次,而临时文件被出乎意料的删除(临时文件由 tmpfile 函数创建在系统临时目录下,文件名由系统随机生成)。在 c++ 程序中清空会更糟,因为静态目标的析构函数可以被错误的执行。

还有一些特殊情况,比如守护进程,他们的父进程需要调用 _exit 而不是子进程。对于大多数情况,exit 在每一次进入 main 函数后只调用一次即可。

关于实现:https://blog.csdn.net/gatieme/article/details/51638706