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

单io_context运行多进程遇超时问题:为何所有任务均超时?

问题分析:单io_context下进程任务全部超时的原因

我修改了某个示例,改用main函数中定义的单个io_context对象,在多线程任务中运行所有进程。原本预期所有任务都能成功完成(因为任务耗时应该小于设置的20ms超时),但实际所有任务都超时了,这是什么原因?

#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <iostream>

using duration = std::chrono::system_clock::duration;
namespace asio = boost::asio;
using namespace std::chrono_literals;

std::string ExecuteProcess(boost::filesystem::path  exe,
                           std::vector<std::string> args, //
                           duration                 time, //
                           std::error_code&         ec, 
               asio::io_context&        ioc) {
    namespace bp = boost::process;
    std::future<std::string> data, err_output;

    bp::group g;
    bp::child child(exe, args, ioc, g, bp::error(ec),
                    bp::std_in.null(),  //
                    bp::std_out > data, //
                    bp::std_err > err_output);

    if (std::error_code ignore; child.running()) {
        g.terminate(ignore);
    }

    if (data.wait_for(time) == std::future_status::ready) {
        ec.clear();
        return data.get();
    }

    ec = make_error_code(asio::error::timed_out);
    return {};
}

int main() {
    constexpr duration timeout = 20ms;
    constexpr auto     script2  = "sleep 0.00005; echo -n 'Hello world'";
    constexpr auto     script1 = "/usr/bin/curl http://httpbin.org/ip -m 5";

    asio::io_context         ioc;
 
    boost::asio::detail::thread_group collect_threads;
    for (int i = 0 ; i < 20 ; i++) {
        collect_threads.create_thread([&]() {
            std::error_code ec_;
            auto s = ExecuteProcess("/bin/bash",    {"-c", script2}, timeout, ec_, ioc);
            std::cout << "got " << ec_.message() << ": " << s << std::endl;
        });
    }
    ioc.run();
}

核心原因:子进程被提前终止

看ExecuteProcess里这段致命代码:

if (std::error_code ignore; child.running()) {
    g.terminate(ignore);
}

这行代码在子进程刚创建完成后,立刻检查进程是否在运行,只要是就直接终止整个进程组。子进程刚启动还没来得及执行脚本内容就被杀死了,导致关联的std::future永远不会就绪,后续data.wait_for(time)必然超时。

之所以会触发这个逻辑,是因为子进程启动需要极短的时间窗口,child.running()在创建后几乎一定会返回true。

修复方案

直接删掉这段错误的终止代码,子进程就能正常执行完成,std::future会在脚本输出后就绪,就能正确获取到结果。


关于waitpid与child.exit_code()返回383的疑问

child.exit_code()返回383(十六进制0x17F),本质是因为进程还没终止。Boost Process的exit_code()只有在进程完全退出并被回收后,才会返回有效的退出码。若用waitpid(pid, &status, WNOHANG)实现轮询,注意以下两点:

  • WNOHANG是非阻塞调用,若进程仍在运行,waitpid会返回0,此时不能调用child.exit_code(),进程状态还未更新。
  • 必须等waitpid返回大于0的pid(表示进程已退出)或返回-1(出错)后,再调用child.exit_code()才能得到正确值。

另外,更推荐用Boost Process的异步接口配合io_context定时器实现超时,这更符合Asio的异步设计模式,比手动调用waitpid更简洁可靠。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 16:57:15