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

使用boost::process管道链时无法关闭stdin致进程无法终止

问题描述

我有多个C语言工具,每个工具从stdin读取数据、处理后将结果写入stdout,当stdin关闭时停止运行。简化的子进程代码如下:

child.c

#include <stdio.h>

int main() {
    char buf[256];
    int nread;

    do {
        nread = fread(buf, 1, 256, stdin);

        // 数据处理逻辑...

        fwrite(buf, 1, 256, stdout);
    } while (nread > 0);

    return 0;
}

通过bash管道可以将这些工具链式调用,例如:

u1 < data.bin | u2 | u3 | ... | un > result.bin

当第一个进程的stdin读到文件末尾并关闭后,链中所有进程会依次终止。

但用C++的boost::process实现复杂工具链时遇到问题:单个子进程关闭stdin后能正常停止,但用boost::process::pstream或boost::process::pipe连接两个及以上子进程时,关闭第一个子进程的stdin后无反应,第一个进程仍处于等待状态。

正常示例:单个子进程

#include <boost/process.hpp>

namespace bp = boost::process;

int main(int argc, char *argv[]) {
    bp::opstream cstdin;
    bp::ipstream cstdout;

    bp::child c0("child", bp::std_in<cstdin, bp::std_out> cstdout);

    cstdin.pipe().close();
    cstdin.close();

    c0.wait();

    return 0;
}

异常示例:两个子进程

#include <boost/process.hpp>

namespace bp = boost::process;

int main(int argc, char *argv[]) {
    bp::opstream cstdin;
    bp::ipstream cstdout;
    bp::pstream connector;

    bp::child c0("child", bp::std_in<cstdin, bp::std_out> connector);
    bp::child c1("child", bp::std_in<connector, bp::std_out> cstdout);

    cstdin.pipe().close();
    cstdin.close();

    c0.wait();
    c1.wait();

    return 0;
}

运行环境:Debian 10、gcc 8.3、boost 1.80。

解决方案

1. 修正子进程代码(推荐)

子进程中当前固定写入256字节,即使fread返回0(已读到EOF)也会写入空数据,这会导致后续管道阻塞。修改为只写入实际读取的字节数:

// 替换原fwrite语句
fwrite(buf, 1, nread, stdout);

这样当stdin关闭时,nread=0,子进程不会写入任何数据,能直接退出,后续进程也会因上游管道关闭而依次终止。

2. 父进程主动读取输出避免阻塞

如果无法修改子进程代码,父进程需要持续读取最后一个子进程的stdout内容,防止下游进程因管道满而阻塞,进而导致上游进程卡住:

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

namespace bp = boost::process;

int main(int argc, char *argv[]) {
    bp::opstream cstdin;
    bp::ipstream cstdout;
    bp::pipe connector; // 改用单向pipe替代pstream

    bp::child c0("child", bp::std_in<cstdin, bp::std_out> connector);
    bp::child c1("child", bp::std_in<connector, bp::std_out> cstdout);

    // 关闭父进程持有的connector两端中不需要的部分
    connector.close();

    cstdin.pipe().close();
    cstdin.close();

    // 读取cstdout的内容,避免c1阻塞
    std::string line;
    while (std::getline(cstdout, line));

    c0.wait();
    c1.wait();

    return 0;
}

另外,使用bp::pipe替代bp::pstream作为进程间的单向连接更合适,同时父进程要关闭不需要的pipe端点,确保EOF能正确传递给子进程。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:36:29