Linux程序崩溃后应通过父进程监控或systemd自动重启,而非用setjmp/longjmp或signal捕获段错误;重试需判断可重试性与副作用,配合幂等设计和指数退避;自愈依赖超时检测与可观测性,避免在析构或信号处理中重试。

程序崩溃后如何自动重启
Linux 下最直接的方式是让父进程监控子进程退出状态,用 fork() + waitpid() 实现轻量级守护。关键不是“捕获崩溃”,而是接受它会崩,并快速拉起新实例。
常见错误是试图在同一个进程内用 setjmp/longjmp 拦截段错误——这不可靠,C++ 标准不保证其行为,且会破坏栈和 RAII 对象析构。
- 用 shell 启动脚本更稳妥:
while true; do ./myapp; sleep 1; done - 若需父子进程通信(如传递配置变更),改用
execv()替换自身进程,避免 fork 开销 - 注意重试前加短延时(
sleep(1)),否则连续崩溃会打满 CPU 并干扰日志排查
任务失败后怎么安全重试
重试不是简单循环调用函数,核心在于判断“是否可重试”和“是否已产生副作用”。比如网络请求失败可重试,但数据库插入中途失败后重复执行可能造成数据重复。
典型场景:HTTP 请求超时、文件写入被中断、锁获取失败。这些都需要配合幂等性设计或状态检查。
立即学习“C++免费学习笔记(深入)”;
- 用指数退避(
std::this_thread::sleep_for()配合递增 delay)降低下游压力 - 把重试逻辑封装成模板函数,例如:
retry_on_failure([]{ return do_work(); }, 3, std::chrono::seconds(1)) - 避免在析构函数或信号处理函数中触发重试——此时对象状态不确定,
this可能已失效
如何检测并恢复资源泄漏或卡死
真正的“自愈”不靠猜,而靠可观测性。没有心跳检测和超时判定,所谓自愈只是盲目重启。
比如一个长期运行的采集线程卡在 read() 上,不能等它自己醒来,而应在主线程用 std::thread::join() 配合 std::chrono::steady_clock 做超时等待,超时则 std::terminate() 或主动释放句柄后重启该模块。
- 对每个外部依赖(socket、file descriptor、mutex)设置明确超时,不用默认阻塞行为
- 定期检查关键指标:内存 RSS 增长异常、线程数持续上升、某类日志长时间未出现
- 不要依赖
std::atexit()清理资源——进程被kill -9时不会调用它
为什么 std::signal 处理 SIGSEGV 不适合做自愈
因为 C++ 中 std::signal(SIGSEGV, handler) 注册的函数只能做极有限的事:写入 write() 系统调用、调用 _Exit()、访问 volatile 变量。其余任何操作(如抛异常、调用 std::cout、new/delete)都是未定义行为。
换句话说,你无法在 segfault 处理器里“修复问题并继续运行”,最多记录现场后退出。想恢复业务逻辑,必须交给外部进程管理。
- 调试阶段可用
gdb --args ./myapp直接定位崩溃点,比信号处理器更有价值 - 生产环境建议用
systemd的Restart=on-failure替代自实现信号捕获 - 若真要现场 dump,用
backtrace()+write()写到临时文件,别碰 C++ iostream


















