目录
[1. 引言](#1. 引言)
[2. 进程终止的本质](#2. 进程终止的本质)
[3. 进程退出场景](#3. 进程退出场景)
[4. 常见退出方法](#4. 常见退出方法)
[5. 退出码(Exit Code)](#5. 退出码(Exit Code))
[6. exit 函数](#6. exit 函数)
[7. _exit 函数](#7. _exit 函数)
[8. return 退出](#8. return 退出)
[9. 补充:atexit 函数(扩展)](#9. 补充:atexit 函数(扩展))
[10. 总结](#10. 总结)
1. 引言
进程终止是进程生命周期的最后阶段。Linux提供了多种退出方式,每种方式在资源释放、数据刷新、退出码传递上有所不同。本文将详细分析进程终止的本质、退出码含义以及 exit 与 _exit 的区别。
2. 进程终止的本质
释放进程申请的内核数据结构(task_struct、mm_struct等)和用户空间的代码与数据。
3. 进程退出场景
-
代码运行完毕,结果正确:退出码为0;
-
代码运行完毕,结果错误:退出码为非0;
-
代码异常终止 :收到信号(如
SIGSEGV、SIGKILL)。
4. 常见退出方法
正常终止
-
从
main函数return; -
调用
exit(); -
调用
_exit()/_Exit()。
异常终止
-
ctrl + c(SIGINT); -
kill -9(SIGKILL)等信号。
5. 退出码(Exit Code)
退出码是进程返回给父进程的一个整数值,低8位有效。在Shell中可以通过 echo $? 查看上一个命令的退出码。
| 退出码 | 含义 |
|---|---|
| 0 | 成功 |
| 1 | 通用错误 |
| 2 | 命令使用不当 |
| 126 | 权限不足或无法执行 |
| 127 | 命令未找到 |
| 128+n | 被信号n终止 |
| 130 | 被 SIGINT 终止(Ctrl+C) |
| 143 | 被 SIGTERM 终止 |
可以使用
strerror()或perror()获取退出码对应的描述信息。
6. exit 函数
c
#include <stdlib.h>
void exit(int status);
exit 在调用 _exit 之前会执行以下清理工作:
-
执行通过
atexit()或on_exit()注册的清理函数; -
刷新所有标准IO流缓冲区,关闭所有打开的流;
-
调用
_exit(status)。
7. _exit 函数
c
#include <unistd.h>
void _exit(int status);
_exit 会立即进入内核,不做任何用户态清理(不刷新缓冲区、不执行 atexit 函数)。
示例对比
c
// 使用 exit
printf("hello"); // 没有换行,仍在缓冲区
exit(0); // 刷新缓冲区,输出 "hello"
// 使用 _exit
printf("hello");
_exit(0); // 不刷新缓冲区,无输出
8. return 退出
在 main 中执行 return n 等价于调用 exit(n),因为 main 的返回值会被运行时函数作为 exit 的参数。
9. 补充:atexit 函数(扩展)
c
#include <stdlib.h>
int atexit(void (*function)(void));
可以注册多个函数,在 exit 调用时按注册相反顺序执行。常用于资源释放、日志记录等。
10. 总结
-
希望完整清理和刷新数据时使用
exit或return; -
需要立即终止、不执行任何清理时使用
_exit; -
退出码是父子进程通信的重要方式,应规范使用。