linux下最直接的方式是用systemd管理进程自动重启,通过restart=always实现崩溃即重启,并在c++中自行实现任务级重试逻辑。

程序崩溃后如何自动重启进程
Linux 下最直接的方式是用 systemd 管理进程生命周期,而不是在 C++ 里自己 fork + waitpid 做守护——后者容易陷入竞态、信号处理混乱,且无法可靠捕获 segfault 或 abort。用 systemd 更轻量、更健壮。
关键配置项:Restart=always(含 crash、exit、signal)、RestartSec=1(重启延迟)、StartLimitIntervalSec=0(禁用启动频率限制,避免因连续失败被封禁)。
- 不要在 C++ 中调用
fork()后自行execv(),信号屏蔽、文件描述符继承、std::atexit 处理器残留都会导致行为不可控 - 如果必须嵌入式部署无 systemd 环境,可用
supervisord或简单 shell wrapper:检查$?是否非零,sleep 后 exec,但需注意 stdout/stderr 重定向丢失日志 -
Restart=on-failure不会重启因exit(0)正常退出的进程,调试时容易误判“没重启”,建议开发期先用always
关键任务失败后如何安全重试
重试不是简单循环调用函数,核心是区分错误类型:网络超时可重试,权限拒绝或数据损坏通常不该重试,否则可能放大问题。
典型模式是带退避的有限重试,C++17 起推荐用 std::this_thread::sleep_for() 配合指数退避,避免 busy-wait 或固定延时打爆下游。
- 必须检查错误码来源:比如
curl_easy_perform()返回CURLE_COULDNT_CONNECT可重试,CURLE_HTTP_RETURNED_ERROR要看响应状态码再决定 - 重试次数上限建议设为 3–5 次,超过则记录
ERROR: failed after N retries并触发告警,而非静默吞掉异常 - 涉及状态变更的操作(如 POST 提交订单)必须幂等:服务端加 idempotency key,客户端重试时复用同一 key,否则重复扣款
如何捕获未处理异常并防止程序静默退出
默认情况下,未捕获的 std::exception 会调用 std::terminate(),进而调用 std::abort(),进程直接终止,不执行栈展开后的析构——资源泄漏、日志截断、共享内存未清理都可能发生。
务必安装全局异常处理器:std::set_terminate(),并在其中做最小化现场保存(如写入 /tmp/app-crash-<pid>.log</pid>),然后调用 _exit(128 + SIGABRT) 避免二次析构。
- 不要在 terminate handler 中抛出新异常、调用
std::cout(可能已被销毁)、或调用任何可能分配内存的函数 -
std::set_unexpected()已弃用(C++17),无需处理;信号如SIGSEGV需单独用sigaction()注册,但注意 signal handler 中只能调用 async-signal-safe 函数 - 若使用第三方库(如 Boost.Asio),确认其是否覆盖了默认 terminate handler,冲突时以你自己的为准
自愈边界在哪:哪些问题根本没法靠重试/重启解决
自愈机制只对临时性故障有效:网络抖动、短暂服务不可用、瞬时资源争用。它对结构性缺陷完全无效,比如配置文件路径写错、证书过期、数据库 schema 不匹配、或逻辑 bug 导致每次运行都崩溃。
这类问题重启只会反复失败,形成“崩溃→重启→再崩溃”循环,掩盖真实根因。此时需要的是可观测性支持:采集 core dump、记录启动参数、比对 config hash、检查依赖版本。
- 每次启动时校验关键配置是否存在且可读,失败立即
_exit(1)并输出明确错误,别等到业务逻辑里才报 “file not found” - 在 systemd service 文件中启用
LogRateLimitIntervalSec=0和LogRateLimitBurst=0,避免日志限频掩盖连续失败 - 重试逻辑里加入 “fail-fast” 判断:比如首次连接数据库失败时,先 ping 一下 host + port 是否通,不通就跳过重试直接退出
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











