You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Boost Process在独立线程读取子进程stdout且不阻塞主程序

解决Boost Process异步监控子进程stdout同时执行主程序任务的问题

嘿,我完全懂你的困扰!Boost Process的官方示例有时候确实会给人一种“异步操作也会阻塞主流程”的错觉,但其实只要调整一下事件循环的使用方式,就能轻松实现边监控子进程输出边跑主程序自己的逻辑

核心思路

关键在于利用Boost Asio的io_context来统一调度所有异步任务——包括子进程的stdout读取,以及主程序自己的业务逻辑。这样两者就能在同一个事件循环里并发执行,互不阻塞。

完整代码示例

1. 子进程代码(每隔5秒输出内容)

先写个简单的子进程程序,模拟每5秒向stdout打印信息:

// child_process.cpp
#include <iostream>
#include <chrono>
#include <thread>

int main() {
    int count = 0;
    while (true) {
        std::cout << "子进程输出:第" << ++count << "次消息" << std::endl;
        std::cout.flush(); // 一定要刷新缓冲区,否则主进程可能读不到
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
    return 0;
}

2. 主程序代码(异步监控+执行自身任务)

主程序用async_pipe建立异步管道,异步读取子进程stdout,同时在事件循环里加入自己的定时任务:

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

namespace bp = boost::process;
namespace asio = boost::asio;

// 异步读取子进程stdout的回调函数
void read_stdout(asio::async_pipe& pipe, char* buffer, std::size_t buffer_size) {
    pipe.async_read_some(
        asio::buffer(buffer, buffer_size),
        [&](const boost::system::error_code& ec, std::size_t bytes_read) {
            if (!ec) {
                // 处理读取到的内容
                std::cout << "[主进程收到]:" << std::string(buffer, bytes_read);
                // 继续发起下一次异步读取,保持持续监控
                read_stdout(pipe, buffer, buffer_size);
            } else if (ec != asio::error::eof) {
                std::cerr << "读取子进程输出出错:" << ec.message() << std::endl;
            }
        }
    );
}

// 主程序自己的任务:每隔2秒打印一次状态
void main_task(asio::io_context& io_context) {
    std::cout << "[主程序]:正在执行自身任务..." << std::endl;
    // 2秒后再次执行该任务,形成循环
    io_context.post([&]() {
        asio::steady_timer timer(io_context, std::chrono::seconds(2));
        timer.async_wait([&](const boost::system::error_code&) {
            main_task(io_context);
        });
    });
}

int main() {
    asio::io_context io_context;
    bp::async_pipe stdout_pipe(io_context);

    // 启动子进程,将其stdout重定向到异步管道
    bp::child child_process(
        "./child_process", // 子进程可执行文件路径
        bp::std_out > stdout_pipe,
        io_context
    );

    // 初始化缓冲区,开始异步读取子进程stdout
    char buffer[1024];
    read_stdout(stdout_pipe, buffer, sizeof(buffer));

    // 启动主程序自己的任务
    main_task(io_context);

    // 运行事件循环,调度所有异步任务
    io_context.run();

    return 0;
}

关键细节说明

  • async_pipe的使用:这是实现异步IO的核心,它替代了普通的管道,支持Boost Asio的异步操作接口。
  • 循环异步读取:在read_stdout的回调里,必须再次调用read_stdout发起下一次读取,否则只能获取到子进程的一次输出。
  • 主程序任务的调度:通过io_context::post和定时器,把主程序的业务逻辑加入事件循环,这样它会和子进程的读取任务交替执行,不会阻塞。
  • 缓冲区刷新:子进程里一定要用std::cout.flush(),否则输出会被缓冲,主进程无法及时收到内容。

运行效果

启动主程序后,你会看到:

[主程序]:正在执行自身任务...
[主进程收到]:子进程输出:第1次消息
[主程序]:正在执行自身任务...
[主程序]:正在执行自身任务...
[主进程收到]:子进程输出:第2次消息
...

主程序的任务每2秒执行一次,子进程的输出每5秒被主进程捕获一次,两者完全并行,互不干扰。

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

火山引擎 最新活动