• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
sn-genuine
博客园    首页    新随笔    联系   管理    订阅  订阅

Linux 进程终止C/C++

Linux 进程终止C/C++笔记


一、进程终止的8种方式

1. 正常终止(5种)

  1. main() 函数中使用 return 返回
  2. 程序任意位置调用 exit() 函数
  3. 程序任意位置调用 _exit() 或 _Exit() 函数
  4. 多线程程序中,最后一个线程从启动例程(线程主函数)使用 return 返回
  5. 多线程程序中,最后一个线程调用 pthread_exit() 返回

2. 异常终止(3种)

  1. 调用 abort() 函数中止
  2. 收到未捕获的信号(如 SIGKILL、SIGSEGV)
  3. 最后一个线程被取消并响应取消请求

二、进程终止状态

  • 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的析构函数
}

六、易错点总结

  1. return 和 exit() 都能正常终止进程,但资源释放行为不同。
  2. exit() 只会执行全局对象析构和 atexit 函数,局部对象析构不会被调用。
  3. _exit()/_Exit() 直接退出,不执行任何清理操作。
  4. atexit() 函数调用顺序与登记顺序相反,且仅在 exit() 或 main 正常返回时触发。
posted on 2026-05-07 14:24  SobNov  阅读(26)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3