Linux 进程终止C/C++
Linux 进程终止C/C++笔记
一、进程终止的8种方式
1. 正常终止(5种)
main()函数中使用return返回- 程序任意位置调用
exit()函数 - 程序任意位置调用
_exit()或_Exit()函数 - 多线程程序中,最后一个线程从启动例程(线程主函数)使用
return返回 - 多线程程序中,最后一个线程调用
pthread_exit()返回
2. 异常终止(3种)
- 调用
abort()函数中止 - 收到未捕获的信号(如
SIGKILL、SIGSEGV) - 最后一个线程被取消并响应取消请求
二、进程终止状态
main()函数中return的返回值即为进程终止状态。- 若程序没有
return语句,也未调用exit(),进程终止状态默认为0。 - 在 Shell 中,可通过
echo $?查看上一个进程的终止状态。 - 进程异常终止时,终止状态为非
0。
三、进程终止相关函数对比
| 函数 | 头文件 | 作用 | 是否调用全局对象析构 | 是否调用局部对象析构 | 是否执行清理(atexit) |
|---|---|---|---|---|---|
return |
无(C++关键字) | 函数返回,结束进程(仅在 main 中) |
是 | 是 | 是 |
exit() |
<stdlib.h> |
正常终止进程 | 是 | 否 | 是 |
_exit()/_Exit() |
<unistd.h>/<stdlib.h> |
直接终止进程 | 否 | 否 | 否 |
abort() |
<stdlib.h> |
异常终止进程(产生核心转储) | 否 | 否 | 否 |
注意:
exit()和_Exit()由 ISO C 标准说明,_exit()由 POSIX 标准说明。
四、atexit() 进程终止处理函数
1. 作用
进程可以用 atexit() 登记终止函数(最多 32 个),这些函数将在 exit() 被调用时自动执行。
2. 函数原型
#include <stdlib.h>
int atexit(void (*function)(void));
3. 执行规则
- 调用顺序:与登记顺序相反(先登记的后执行,后登记的先执行)
- 触发条件:只有
exit()或main()函数正常返回时才会触发;_exit()/abort()不会触发
4. 示例代码
#include <iostream>
#include <cstdlib>
using namespace std;void func1() {cout << "调用了func1()\n";
}void func2() {cout << "调用了func2()\n";
}int main() {atexit(func1); // 登记第1个进程终止函数atexit(func2); // 登记第2个进程终止函数return 0;
}
输出顺序:
调用了func2()
调用了func1()
五、资源释放问题(return vs exit())
1. return(在 main 中)
- 会调用局部对象的析构函数
- 会调用全局对象的析构函数
- 会执行
atexit()登记的终止函数
2. exit()
- 不会调用局部对象的析构函数
- 会调用全局对象的析构函数
- 会执行
atexit()登记的终止函数
3. _exit()/_Exit()
- 不会调用任何对象的析构函数
- 不会执行
atexit()登记的终止函数 - 直接终止进程,仅关闭文件描述符
示例代码(析构函数对比)
#include <iostream>
#include <cstdlib>
using namespace std;struct AA {string name;AA(const string &str) : name(str) {}~AA() {cout << name << "调用了析构函数。\n";}
};AA a1("对象a1"); // 全局对象int main() {AA a2("对象a2"); // 局部对象// return 0; // 会调用a2和a1的析构函数exit(0); // 只会调用a1的析构函数,不会调用a2的析构函数
}
六、易错点总结
return和exit()都能正常终止进程,但资源释放行为不同。exit()只会执行全局对象析构和atexit函数,局部对象析构不会被调用。_exit()/_Exit()直接退出,不执行任何清理操作。atexit()函数调用顺序与登记顺序相反,且仅在exit()或main正常返回时触发。
