Opened 5 years ago
#13103 new Bugs
Documentation: Line-by-line I/O example should use asio
Reported by: | 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(); };