带有标准输出重定向的`boost :: process`在Ubuntu 16中随机失败
Posted
技术标签:
【中文标题】带有标准输出重定向的`boost :: process`在Ubuntu 16中随机失败【英文标题】:`boost::process` with standard output redirection fails randomly with Ubuntu 16 【发布时间】:2018-03-06 21:02:04 【问题描述】:我尝试使用boost::process
,它看起来像是 boost 中非常错误的部分;无论如何,可能有人知道解决方法。
最常见的任务是执行流程并获得其完整(真正完整)的输出。通常输出也可能是二进制的,因此我们不能在一般情况下使用string
。
来自boost
文档的异步示例不起作用,论坛上的其他文章已经提到过,所以我尝试使用最简单的同步算法。当然,我知道死锁风险,但是boost
没有走到这一步,它之前就失败了。
代码思路如下:
bool ReadPipe(boost::process::ipstream &pipe, vector<char> &output)
char buffer[4096];
pipe.read(buffer, 4096);
auto bytesRead = pipe.gcount();
if (bytesRead)
output.insert(output.end(), buffer, buffer + bytesRead);
return bytesRead != 0;
boost::process::ipstream output;
vector<char> processOutput;
string cmdline = "somthing";
boost::process::child c(cmdLine.c_str(),
boost::process::std_in.close(),
boost::process::std_out > output);
while (c.running())
Reader::ReadPipe(output, processOutput);
Reader::ReadPipe(output, processOutput);
在这段代码中,我们创建进程,将其标准输出重定向到ipstream
,在应用程序运行时读取它,并在应用程序存在后读取可能的其余数据。
在 Windows 上运行正常。在 Ubuntu 16 上它有时可以工作,有时返回部分输出,有时不返回任何输出。
有谁知道它为什么如此不稳定,有没有任何现实的方法可以使用boost::process
从任何应用程序获取完整的、可能是二进制的输出,就像 Linux 终端可以做到的那样?
【问题讨论】:
哪些命令可以提供部分输出?对于特定命令是否一致,或者同一命令有时会给出完整的输出,有时不会?我注意到您没有重定向标准错误;也许缺少的输出正在那里写。 我以同样的方式重定向stderr
,我只是简化了示例。我使用adb
命令(android 调试桥)对其进行测试,例如,adb shell ifconfig
有时会返回完整输出,有时则不会。
【参考方案1】:
使用running()
会引发竞争条件。
如果程序在您消耗完所有输出之前退出,您将停止消耗。这就是你编码的明确内容。
仔细观察
使用这个人为的例子来加剧问题,以便可靠地复制它:
#include <boost/process.hpp>
namespace Reader
static constexpr size_t buf_size = 4096;
bool ReadPipe(boost::process::ipstream &pipe, std::vector<char> &output)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
char buffer[buf_size];
pipe.read(buffer, sizeof(buffer));
auto bytesRead = pipe.gcount();
if (bytesRead)
output.insert(output.end(), buffer, buffer + bytesRead);
return bytesRead != 0;
#include <iostream>
int main()
boost::process::ipstream output;
std::vector<char> processOutput;
std::string cmdline = "/bin/bash";
boost::process::child c(cmdline.c_str(), std::vector<std::string> "-c", "(dd if=/dev/urandom bs=1024 count=10 | xxd); echo -e '\\nComplete, bye!'" ,
boost::process::std_in.close(),
boost::process::std_out > output);
while (c.running())
Reader::ReadPipe(output, processOutput);
std::cout.write(processOutput.data(), processOutput.size()) << std::endl;
将输出通过|tail
打印出类似
如您所见,它确实是不完整的。减小 dd 大小,例如
boost::process::child c(cmdline.c_str(), std::vector<std::string> "-c", "(dd if=/dev/urandom bs=32 count=10 | xxd); echo -e '\\nComplete, bye!'" ,
显示预期
路上有一只熊
有一个丑陋的问题:tutorial example 有以下不祥的警告:
因此,实际上在进程退出后是否可以安全地清空输入缓冲区并不完全清楚。我的直觉告诉我这实际上很好,但更重要的是,事情可以简单得多:
幸运的是,我们可以飞(而熊不能)
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <iostream>
int main()
std::future<std::vector<char>> processOutput;
std::string cmdline = "/bin/bash";
boost::asio::io_service io;
boost::process::child c(cmdline.c_str(), std::vector<std::string> "-c", "(dd if=/dev/urandom bs=1024 count=10 | xxd); echo -e '\\nComplete, bye!'" ,
boost::process::std_in.close(),
boost::process::std_out > processOutput,
io);
io.run();
c.wait();
auto output = processOutput.get();
std::cout.write(output.data(), output.size()) << std::endl;
这在没有竞争条件的情况下按预期工作。对于更复杂的用法(例如与输入动态确定输出的子进程的“实时”对话),请考虑使用异步接口,例如boost process running() and exit_code() thread safety 或 Boost::process output blank lines
【讨论】:
如果子进程输出大于管道缓冲区的大小,这不会也死锁吗? @DanielTrebbien 如果您使用可能发生的固定大小的缓冲区。但是,我的示例都没有使用固定大小的缓冲区。 (具有讽刺意味的是,我错过了您的评论,现在才看到它,因为我在这里的最后一个示例中spotted a bug lurking)以上是关于带有标准输出重定向的`boost :: process`在Ubuntu 16中随机失败的主要内容,如果未能解决你的问题,请参考以下文章