You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost Process on_exit回调重启进程后程序崩溃问题排查求助

进程重启后崩溃及Valgrind报错的修复方案

问题描述

尝试在旧进程退出后立即重启相同进程,执行几次后程序崩溃。Valgrind报告与handler相关的无效读写操作,移除lambda内启动新进程的调用后,Valgrind错误消失。示例代码仅针对单个进程,目标是让多个此类可自重启的进程同时运行:

std::function<void(int, const std::error_code&)> on_exit;
on_exit = [this, &on_exit](int exit, const std::error_code& ec_in) {
    // error handling
    client.wait();
    client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
};
client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
io_context.run();

注:client、path_to_client和io_context均为类成员变量。

问题根源

lambda中捕获了on_exit的引用,而std::function是可移动/可赋值的对象。每次在lambda内重启进程时,bp::child会持有这个handler的引用,后续重新赋值on_exit或销毁原std::function对象时,会导致handler调用时访问无效内存地址,触发Valgrind的无效读写报错。

修复方案

1. 用智能指针保证handler生命周期安全

避免捕获on_exit的引用,改用std::shared_ptr包裹std::function,让lambda捕获智能指针副本,确保handler在所有引用者使用期间不会被销毁:

auto on_exit = std::make_shared<std::function<void(int, const std::error_code&)>>();
*on_exit = [this, on_exit](int exit_code, const std::error_code& ec) {
    // error handling
    client.wait();
    client = bp::child(path_to_client, io_context, bp::on_exit=*on_exit);
};
client = bp::child(path_to_client, io_context, bp::on_exit=*on_exit);
io_context.run();

2. 优化client对象的替换方式

直接赋值client = bp::child(...)会销毁原有bp::child对象,可能导致旧对象持有的handler引用失效。改用swap操作避免生命周期冲突:

*on_exit = [this, on_exit](int exit_code, const std::error_code& ec) {
    // error handling
    client.wait();
    bp::child new_client(path_to_client, io_context, bp::on_exit=*on_exit);
    client.swap(new_client);
};

3. 多进程场景的额外注意事项

  • 每个自重启进程需独立持有自己的handler智能指针,避免多进程共享同一handler引发竞态或生命周期问题。
  • 若使用多线程运行io_context,需用io_context::strand序列化handler执行,防止并发修改client等类成员变量。

内容的提问来源于stack exchange,提问作者luxean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:15:03