如何通过异步运行boost子进程来测试实例计数器?

时间:2018-03-24 09:05:50

标签: boost parallel-processing boost-asio boost-process

我尝试使用带有async_pipe的 boost :: childprocess ,如下面的代码示例所示,同时期望有一个wait方法,运行调用不会等待被调用可执行文件在继续到我调用 wait()的行之前完成。我的目标是多次启动相同的可执行文件,以便在GTest中测试实例计数方法(基于boost托管共享内存段实现)。 但是在这里我需要调用 io_service :: run(),而不是等待被调用的可执行文件完成,就像现在一样。有人能告诉我在哪里使用它错了吗?或者,如果这是对我的功能进行单元测试的错误方法?我一直试图找到解决方案已经有一段时间了! 以下是我如何调用可执行文件的一个实例的示例:

int CallChildProcess_Style9() {

std::string strCmdLine = "E:\\file.exe --Debug MainStartUps_Off --Lock 3";
boost::asio::io_service m_oIOS;
std::vector<char>       m_oAsyncBuffer_Out;
bp::async_pipe          m_oAsyncPipe_Out(m_oIOS);
std::error_code         build_ec;
size_t                  nReadSize(0);
boost::scoped_ptr<boost::process::child>  m_pChildProcess(nullptr);

m_pChildProcess.reset(new bp::child(strCmdLine.data(), bp::std_out > m_oAsyncPipe_Out, build_ec));

m_oAsyncBuffer_Out.resize(1024*8);

boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
    [&](const boost::system::error_code &ec, std::size_t size) { nReadSize = size; });

size_t iii = m_oIOS.run();

m_pChildProcess->wait();
m_oAsyncBuffer_Out.resize(nReadSize);

std::string strBuf(m_oAsyncBuffer_Out.begin(), m_oAsyncBuffer_Out.begin() + nReadSize);

int         result = m_pChildProcess->exit_code();

m_oAsyncPipe_Out.close();

m_oIOS.reset();

return result;

}

1 个答案:

答案 0 :(得分:0)

使用io_service

要使用async_pipe,您需要将io_service个实例提供给bp::child的参数关键字:

#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>

namespace bp = boost::process;

int CallChildProcess_Style9() {

    std::string strCmdLine = "/bin/cat";
    boost::asio::io_service m_oIOS;
    std::vector<char> m_oAsyncBuffer_Out;
    bp::async_pipe m_oAsyncPipe_Out(m_oIOS);
    std::error_code build_ec;

    size_t nReadSize(0);
    boost::scoped_ptr<boost::process::child> m_pChildProcess(nullptr);

    std::vector<std::string> const args = { "/home/sehe/Projects/stackoverflow/test.cpp" };
    m_pChildProcess.reset(new bp::child(strCmdLine, args, bp::std_out > m_oAsyncPipe_Out, build_ec, m_oIOS));

    std::cout << "Launched: " << build_ec.message() << std::endl;

    m_oAsyncBuffer_Out.resize(1024 * 8);

    boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
        [&](const boost::system::error_code &ec, std::size_t size) {
            std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
            nReadSize = size;
        });

    std::cout << "read started" << std::endl;
    size_t iii = m_oIOS.run();

    std::cout << "io_service stopped" << std::endl;
    std::cout << "initiate child::wait" << std::endl;
    m_pChildProcess->wait();
    std::cout << "wait completed" << std::endl;

    std::string const strBuf(m_oAsyncBuffer_Out.data(), nReadSize);

    int result = m_pChildProcess->exit_code();

    m_oAsyncPipe_Out.close();

    m_oIOS.reset();

    return result;
}

int main() {
    CallChildProcess_Style9();
}

打印

http://coliru.stacked-crooked.com/a/8a9bc6bed3dd5e0a

Launched: Success
read started
read completion handler: size = 1589 (End of file)
io_service stopped
initiate child::wait
wait completed

挂起孩子

即使已修复,async_pipe::async_read也只会读取,直到缓冲区已满或达到EOF。如果子进程输出的缓冲区大小超过缓冲区大小(样本中为8k),那么它将卡住并且永远不会完成。

例如:替换这样的命令:

std::string strCmdLine = "/usr/bin/yes";

结果

Live on Coliru

Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait

它将悬挂到无限远。这是,因为yes具有无限输出。任何具有大输出的命令都将挂起(例如/bin/cat /etc/dictionaries-common/words以相同的方式挂起)。您可以通过查看strace输出来证明这一点:

$ sudo strace -p $(pgrep yes)

strace: Process 21056 attached
write(1, "/home/sehe/Projects/stackoverflo"..., 8170

最简单的方法来修复&#34;这将是在您填满输出缓冲区后关闭输出接收器:

boost::asio::async_read(m_oAsyncPipe_Out, boost::asio::buffer(m_oAsyncBuffer_Out),
    [&](const boost::system::error_code &ec, std::size_t size) {
        std::cout << "read completion handler: size = " << size << " (" << ec.message() << ")" << std::endl;
        nReadSize = size;
        m_oAsyncPipe_Out.close();
    });

这要求您在致电wait()之前预期孩子退出,以便wait()可能失败:

<强> Live On Coliru

Launched: Success
read started
read completion handler: size = 8192 (Success)
io_service stopped
initiate child::wait
wait completed (Success)

退后一步:你需要什么?

但是,看起来你可能会变得复杂。如果您乐意将输出限制为8k,并且您需要的是拥有多个副本,为什么还要使用异步io?

任何child都已异步,您只需传递缓冲区:

<强> Live On Coliru

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

namespace bp   = boost::process;
using Args     = std::vector<std::string>;
using Buffer8k = std::array<char, 8192>;

int main() {
    auto first_out  = std::make_unique<Buffer8k>(),
         second_out = std::make_unique<Buffer8k>();

    *first_out = {};
    *second_out = {};

    boost::asio::io_service svc;

    bp::child first("/bin/echo", Args{"-n", "first"}, bp::std_out > boost::asio::buffer(*first_out), svc);
    bp::child second("/bin/echo", Args{"-n", "second"}, bp::std_out >boost::asio::buffer(*second_out), svc);

    std::cout << "Launched" << std::endl;

    svc.run();
    first.wait();
    second.wait();

    std::string const strFirst(first_out->data()); // uses NUL-termination (assumes text output)
    std::string const strSecond(second_out->data()); // uses NUL-termination (assumes text output)

    std::cout << strFirst << "\n";
    std::cout << strSecond << "\n";

    return first.exit_code();
}

打印

Launched
first
second

更多例子

因为我无法确定您需要什么,所以请查看我写的实际显示实时异步IO的其他示例,您可能需要响应一个进程的特定输出。