Search code examples
c++boostboost-asioboost-process

async_read on async_pipe child process giving no data


I have the following code which is simplified from my real code where I am trying to do an async_read on an async_pipe connected to a child process. In the child process I am calling "ls ." as just a test and I want my async read to get the result of that. It returns the following

$ ./a.out
system:0
0

Why does this happen I cannot figure out? Ideally I want to replace "ls ." with a long running process where I can read line after line with async_read.

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <boost/process.hpp>

namespace bp = boost::process;

class test {
private:
  boost::asio::io_service ios;
  boost::asio::io_service::work work;
  bp::async_pipe ap;
  std::vector<char> buf;

public:
  test()
    : ios(), work(ios), ap(ios) {
  }

  void read(
      const boost::system::error_code& ec,
      std::size_t size) {
    std::cout << ec << std::endl;
    std::cout << size << std::endl;
  }

  void run() {
    bp::child c(bp::search_path("ls"), ".", bp::std_out > ap);
    boost::asio::async_read(ap, boost::asio::buffer(buf),
      boost::bind(&test::read,
                  this,
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));

    ios.run();
  }
};

int main() {
  test c;
  c.run();
}

Solution

  • You read into a vector of size 0.

    You read 0 bytes. That's what you asked for.

    I'd suggest using a streambuf and just reading till EOF. Also, drop work unless you really did want run() to never return:

    Live On Coliru

    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <boost/process.hpp>
    #include <iostream>
    
    namespace bp = boost::process;
    
    class test {
      private:
        boost::asio::io_service ios;
        bp::async_pipe ap;
        boost::asio::streambuf buf;
    
      public:
        test() : ios(), ap(ios) {}
    
        void read(const boost::system::error_code &ec, std::size_t size) {
            std::cout << ec.message() << "\n";
            std::cout << size << "\n";
            std::cout << &buf << std::flush;
        }
    
        void run() {
            bp::child c(bp::search_path("ls"), ".", bp::std_out > ap, ios);
    
            async_read(ap, buf, boost::bind(&test::read, this, _1, _2));
    
            ios.run();
        }
    };
    
    int main() {
        test c;
        c.run();
    }
    

    Prints, e.g.

    End of file
    15
    a.out
    main.cpp