使用 boost::process 读取 cout 并写入进程的 cin

Posted

技术标签:

【中文标题】使用 boost::process 读取 cout 并写入进程的 cin【英文标题】:Read cout and write to cin of a process with boost::process 【发布时间】:2019-07-30 00:07:38 【问题描述】:

我正在尝试生成一个 shell 并读取标准输出和标准错误,并让用户通过写入标准输入来运行命令。我似乎无法从 stdout 或 stderr 读取数据,而且写入 stdin 显然也无济于事。

如果我不尝试重定向任何 stdin、stdout 或 stderr,它会生成一个正常的 shell,就像我期望的那样。然而,重定向它们只会让一切都消失。 >> 只是神秘地挂起。我从孩子的标准输出中取出,然后将其放回实际的标准输出中,所以我希望至少会出现类似我的用户名的内容,但就像我说的那样,它只是阻塞,因为缓冲区中必须没有任何内容。

boost::process::child shell;
boost::process::opstream instream;
boost::process::ipstream errstream;
boost::process::ipstream outstream;

void console_out_read()

    char ch;
    do
    
        outstream >> ch;
        std::cout << ch;
    
    while(true);


void console_err_read()

    char ch;
    do
    
        errstream >> ch;
        std::cerr << ch;
    
    while(true);


void console_in_write()

    int ch;
    do
    
        std::cin >> ch;
        instream << ch;
    
    while(true);


int main()

    std::error_code ec;

    shell = boost::process::child("bash",
        boost::process::std_out > outstream,
        boost::process::std_err > errstream,
        boost::process::std_in < instream,
        ec);

    boost::thread cro(console_out_read);
    boost::thread cre(console_err_read);
    boost::thread cwi(console_in_write);
    shell.wait();
    return 0;

【问题讨论】:

console_out_read 永远不会对 ch 做任何事情并且永远不会返回。 【参考方案1】:

您发布的代码存在几个问题。

首先,在console_in_write 中,您将ch 声明为int 而不是char。这意味着std::cin 将只接受看起来像数字的东西。如果您输入的不是数字,这会导致std::cin 进入错误状态。

其次,即使将ch 更改为charstd::cin &gt;&gt; ch 也永远不会读取换行符,因为格式化的输入操作会丢弃空格。解决这个问题最简单的方法是使用std::getline 逐行读取而不是逐字符读取,并且在您读取的每一行之后写一个换行符。

第三,boost 的管道流是完全缓冲的。这意味着您需要在编写换行符后刷新流,以便将数据发送到您的子进程。否则,您将键入一个命令,但不会发生任何事情,因为数据只是位于流的缓冲区中。

第四,std::threads 在超出范围之前必须是joined 或detached。由于您目前没有对 I/O 线程执行此操作,因此一旦您的子进程退出,父进程就会崩溃。

把这些放在一起,我希望一个最小的例子看起来像这样:

boost::process::child shell;
boost::process::opstream instream;
boost::process::ipstream errstream;
boost::process::ipstream outstream;

void console_out_read()

    std::string line;
    while (std::getline(outstream, line))
    
        std::cout << line << '\n';
    


void console_err_read()

    std::string line;
    while (std::getline(errstream, line))
    
        std::cout << line << '\n';
    


void console_in_write()

    std::string line;
    while (std::getline(std::cin, line))
    
        instream << line << std::endl;
        if (line == "exit") return;
    


int main()

    std::error_code ec;

    shell = boost::process::child("bash",
        boost::process::std_out > outstream,
        boost::process::std_err > errstream,
        boost::process::std_in < instream,
        ec);

    std::thread cro(console_out_read);
    std::thread cre(console_err_read);
    std::thread cwi(console_in_write);
    shell.wait();
    cro.join();
    cre.join();
    cwi.join();

【讨论】:

是否可以在不写换行符的情况下使它们无缓冲或刷新,就像在 c 中一样? 如果你想要原始的无缓冲管道 I/O,你可以传递 boost::process::pipe 而不是 pstream

以上是关于使用 boost::process 读取 cout 并写入进程的 cin的主要内容,如果未能解决你的问题,请参考以下文章

Boost.Process - 如何让一个进程运行一个函数?

如何使用 Boost.Process 从“类型”(Windows)获取跟踪?

Windows 上的 Boost::process - 使用 MinGW?

带有标准输出重定向的`boost :: process`在Ubuntu 16中随机失败

提升进程 running() 和 exit_code() 线程安全

Boost::process child by id