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;
}