Andrew Tomazos
Andrew Tomazos

Reputation: 68698

boost::process async IO example doesn't work?

The following program:

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

namespace bp = boost::process;

int main() {
    boost::asio::io_service ios;
    std::vector<char> buf(4096);

    bp::async_pipe ap(ios);

    bp::child c("/bin/ls", bp::std_out > ap);

    boost::asio::async_read(ap, boost::asio::buffer(buf),
            [](const boost::system::error_code &ec, std::size_t size){});

    ios.run();
    int result = c.exit_code();
    std::cout << result << std::endl;
}

outputs 383. I would expect it to output 0.

This is very nearly a copy-and-paste of the example from:

https://www.boost.org/doc/libs/1_71_0/doc/html/boost_process/tutorial.html#boost_process.tutorial.async_io

Upvotes: 3

Views: 1186

Answers (1)

G.M.
G.M.

Reputation: 12899

There may be a few issues here. Firstly, I think the comment in the documentation...

Passing an instance of boost::asio::io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of wait is needed

...refers to the example after the code you've shown. Specifically...

boost::asio::io_service ios;
std::vector<char> buf(4096);

bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > boost::asio::buffer(buf), ios);

ios.run();
int result = c.exit_code();

Where the io_service is passed by reference to the child ctor.

The comment is also slightly misleading. While it's true that the subsequent call to ios.run() does wait asynchronously for the exit it also appears (boost 1.71.0) that the exit code is not fixed up as one might hope. The exit code is stored within the child class as...

std::shared_ptr<std::atomic<int>> _exit_status;

From a quick scan of the source code it seems _exit_status->store(...) is only invoked from the following members...

boost::process::child::running
boost::process::child::wait
boost::process::child::wait_until

So, even though the process has exited (assuming all went well) when ios.run() returns one or more of running, wait or wait_until must be called to make the exit code available.

As commented elsewhere by @sehe this looks like it's possibly a regression. If I can find a bug report I'll update this. In the meantime the workaround is to simply call c.wait() before c.exit_code().

Upvotes: 4

Related Questions