读取阻塞进程的输出

Reading output of blocking process

我有一些简单的应用程序:

//first.exe

int main()
{
  std::cout << "1" << std::endl;
  std::cout << "2" << std::endl;
  std::cout << "3" << std::endl;

  std::cin.get();

  return 0;
}

当“2”作为子进程出现在应用程序 运行 的标准输出中时,我想在单独的应用程序中调用回调:

//second.exe

int main()
{
  boost::asio::io_context context;
  boost::process::async_pipe out(context);
  boost::asio::streambuf buffer;

  boost::process::child("first.exe", boost::process::std_out > out);

  boost::asio::async_read_until(out, buffer, "2", [](boost::system::error_code code, std::size_t size)
  {
    //do something
  });

  context.run();

  return 0;
}

问题是,由于子进程中的 std::cin.get(),我必须按父进程中的任何按钮才能使 io_context 执行回调函数。您对让它按预期工作有什么建议吗?

在这种情况下,我认为您不需要做任何事情(std::cin 读取可能会失败):

Live On Coliru

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

int main()
{
    namespace bp = boost::process;
    boost::asio::io_context context;
    bp::async_pipe out(context);

    bp::child c("./first.exe", bp::std_out > out);

    boost::asio::streambuf buffer;
    boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "received: " << size << " bytes: ";

            auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());

            std::clog << std::quoted(std::string(b, m)) << std::endl;
            std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;

            buffer.consume(size);
        }
    });

    context.run();
    return c.exit_code();
}

版画

received: 3 bytes: "1
2"
Note that we read more bytes: "
3
"

清洁工

为了清洁,您可以简单地关闭 std_in:

bp::child c("./first.exe", bp::std_out > out, bp::std_in.close());

为了正确起见,还要为异步 io 添加上下文:

bp::child c("./first.exe", bp::std_out > out, bp::std_in.close(), context);

这些都有效(参见 live)。

更复杂

如果您实际上需要提供输入以获得输出怎么办?或者您需要根据输出提供输入?那么评论者是对的:将管道附加到 std_in(或异步写入缓冲区)。

发送固定缓冲区

Live On Coliru

  • first.cpp

    #include <iostream>
    int main() {
        using namespace std;
        string s;
        while (cin >> s)
            cout << "reversed: " << string(s.rbegin(), s.rend()) << endl;
    }
    
  • main.cpp

    #include <boost/process.hpp>
    #include <boost/asio.hpp>
    #include <boost/process/async.hpp>
    #include <iostream>
    #include <iomanip>
    
    int main() {
        namespace bp = boost::process;
        boost::asio::io_context context;
        bp::async_pipe out(context);
    
        std::string i = "hello\nwo2rld\n";
        bp::child c("./first.exe", bp::std_out > out, bp::std_in < boost::asio::buffer(i), context);
    
        boost::asio::streambuf buffer;
        boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
            if (code) {
                std::cerr << "Oops: " << code.message() << std::endl;
            } else {
                std::cerr << "received: " << size << " bytes: ";
    
                auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());
    
                std::clog << std::quoted(std::string(b, m)) << std::endl;
                std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;
    
                buffer.consume(size);
            }
        });
    
        context.run();
        return c.exit_code();
    }
    

版画

received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"

发送动态数据

同步和异步:

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

int main() {
    namespace bp = boost::process;
    boost::asio::io_context context;
    bp::async_pipe out(context), in(context);

    bp::child c("./first.exe", bp::std_out > out, bp::std_in < in, context);

    boost::asio::write(in, boost::asio::buffer("hello ", 6));

    boost::asio::streambuf buffer;
    boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "received: " << size << " bytes: ";

            auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());

            std::clog << std::quoted(std::string(b, m)) << std::endl;
            std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;

            buffer.consume(size);
        }
    });

    boost::asio::async_write(in, boost::asio::buffer("wo2rld\n", 7), [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "sent: " << size << " bytes: ";
        }
    });

    context.run();
    return c.exit_code();
}

再次打印:

sent: 7 bytes: received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"