Opened 5 years ago

#13103 new Bugs

Documentation: Line-by-line I/O example should use asio

Reported by: joshua.hopp@… Owned by:
Milestone: To Be Determined Component: process
Version: Boost 1.64.0 Severity: Problem
Keywords: Cc:

Description

The boost::process Tutorial needs some improvements:

When following the example "Synchronous I/O" the output may be incomplete. Actually, this is even stated in the FAQ: "But, since pipes are buffered, you might get incomplete data if you do this: It is therefore highly recommended that you use the asynchronous api if you are not absolutely sure how the output will look."

Not retrieving all data is not something to be generally expected; therefore this should be stated clearly in the tutorial's example. A new example should provide a solution to the problem. (Would have saved me hours of work!)

Or even better, since the asynchronous api is highly recommended anyway, why not deprecate synchronous IO and replace the example completely?

The new/additional example could look somewhat like this:

#include <boost/process.hpp>
#include <iostream>
#include <functional>
#include <sstream>

// capture process output line by line
int main() {
        const std::string file = "file";

        namespace bp = boost::process;

        bp::opstream os;

        struct IoData {
                bp::async_pipe ap;        // Pipe to be used by the stream
                std::vector<char> buffer;
                std::mutex streamMutex;   
                std::string keepline;     // Store incomplete data
                std::function<void(const std::string&)> callback;

                IoData(boost::asio::io_service& ios_, std::function<void(const std::string&)> callback_)
                : ap(ios_)
                , buffer(512) // Set arbitrary buffer size here!
                , callback(callback_) {
                }
        };

        // set up async io
        boost::asio::io_service ios;

        // Prepare capturing both stdout and stderr
        IoData err(ios, [](const std::string& s){ std::cout << "cerr: " << s <<std::endl; });
        IoData out(ios, [](const std::string& s){ std::cout << "cout: " << s <<std::endl; });

        bp::child process(bp::search_path("nm"), file, bp::std_out > out.ap, bp::std_err > err.ap, ios);

        std::function<void(IoData&)> beginRead = [&](IoData& io) {
                io.ap.async_read_some(boost::asio::buffer(io.buffer, io.buffer.size()), [&](const boost::system::error_code &ec, std::size_t size) {
                                std::lock_guard<std::mutex> guard(io.streamMutex);
                                std::string str(io.buffer.data(), size);

                                std::stringstream stream(io.keepline + str);
                                std::string line;
                                while (std::getline(stream, line)) {
                                        io.callback(line);
                                }
                                if (stream.eof()) {
                                        io.keepline = line;
                                } else {
                                        io.keepline = "";
                                }

                                if (ec.value() != 0) {
                                        return;
                                }

                                beginRead(io);
                });
        };

        beginRead(err);
        beginRead(out);
        ios.run();

        process.wait();

};

Change History (0)

Note: See TracTickets for help on using tickets.