C++ `带有标准输出重定向的进程在Ubuntu 16中随机失败
我尝试使用C++ `带有标准输出重定向的进程在Ubuntu 16中随机失败,c++,boost,C++,Boost,我尝试使用boost::process,它看起来像是boost中非常有缺陷的部分;不管怎样,可能是任何人都知道解决方法 最常见的任务是执行流程并获得其完整(真正完整的)输出。通常输出可能是二进制的,因此我们不能在泛型情况下使用string boost文档中的异步示例不起作用,本论坛的其他文章已经提到了这一点,因此我尝试使用最简单的同步算法。当然,我知道死锁风险,但是boost没有达到这一点,它以前失败过 守则的构思如下: bool ReadPipe(boost::process::ipstrea
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);
boolreadpipe(boost::process::ipstream和pipe、vector和output)
{
字符缓冲区[4096];
管道读取(缓冲区,4096);
auto bytesRead=pipe.gcount();
if(字节读取)
insert(output.end(),buffer,buffer+bytesRead);
返回字节读取!=0;
}
boost::process::ipstream输出;
矢量处理输出;
string cmdline=“somthing”;
boost::process::child c(cmdLine.c_str(),
boost::process::std_in.close(),
boost::进程::标准输出>输出);
while(c.running())
Reader::ReadPipe(输出,processOutput);
Reader::ReadPipe(输出,processOutput);
在这段代码中,我们创建流程,将其标准输出重定向到ipstream
,在应用程序运行时读取它,并在应用程序存在后读取可能的其余数据
在Windows上工作正常。在Ubuntu 16上,它有时工作,有时返回部分输出,有时不返回任何输出
有人知道它为什么如此不稳定吗?有没有什么切实可行的方法可以使用boost::process
从任何应用程序获得完整的、可能是二进制的输出,就像Linux终端可以做到的那样?使用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;
}
显示预期的
路上有一只熊
有一个丑陋的陷阱:有以下不祥的警告:
因此,事实上,在进程退出后清空输入缓冲区是否安全还不完全清楚。我的直觉告诉我这其实很好,但更重要的是,事情可以简单得多:
幸运的是,我们能飞(熊不能)
#包括
#包括
#包括
int main(){
std::未来进程输出;
std::string cmdline=“/bin/bash”;
boost::asio::io_服务io;
boost::process::child c(cmdline.c_str(),std::vector{“-c”,“(dd if=/dev/uradom bs=1024 count=10|xxd);echo-e'\\n完成,再见!”,
boost::process::std_in.close(),
boost::process::std_out>processOutput,
io);
io.run();
c、 等待();
自动输出=processOutput.get();
std::cout.write(output.data(),output.size())什么命令提供部分输出?对于特定的命令是一致的,还是同一命令有时提供完全输出,有时不一致?我注意到您没有重定向stderr;可能丢失的输出正在那里编写。我以同样的方式重定向stderr,我只是简化了示例。我用adb
co测试它例如,adb shell ifconfig
有时返回完整的输出,有时不返回。如果子进程输出超过管道缓冲区的大小,这不会也会死锁吗?@DanielTrebbien如果您使用可能发生的固定大小的缓冲区。但是,我的示例中没有一个使用固定大小的缓冲区。(具有讽刺意味的是,我错过了你的评论,现在才看到,我在这里的最后一个例子中)
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!'" },
#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;
}