What's the correct way of detecting end of pipe for boost::asio::readable_pipe used with Process V2?

7 hours ago 1
ARTICLE AD BOX

I use Process V2 and read its output via boost::asio::readable_pipe. I need to detect whether the reading finished successfully by reaching end of data, or the reading ended because of an error. The behaviour however differs on Linux and Windows after successfully reaching end:

on Linux I get boost::system::error_code whose value() returns 2 and message is "End of file"

on Windows I get boost::system::error_code whose value() returns 109 and message is "The pipe has been ended"

Is there any other platform-independent way to check the end, that doesn't need having conditions on OS?

Here is a complete example:

#include <iostream> #include <string> #include <thread> #include <vector> #include <boost/asio.hpp> #include <boost/asio/buffer.hpp> #include <boost/process/v2/process.hpp> #include <boost/process/v2/stdio.hpp> int main() { boost::asio::io_context ctx; boost::asio::readable_pipe stdOutPipe(ctx); #ifdef unix std::string processName = "/usr/bin/bash"; std::vector<std::string> processArgs = { "-c", "ls", "-al"}; #else std::string processName = std::format("{}\\system32\\cmd.exe", std::getenv("windir")); std::vector<std::string> processArgs = { "/c", "dir"}; #endif boost::process::v2::process process(ctx, processName, processArgs, boost::process::v2::process_stdio{ {}, stdOutPipe, {} }); std::jthread printStdOutThread([&] { while (true) { std::string stdOut; boost::system::error_code ec; size_t stdOutLength = boost::asio::read(stdOutPipe, boost::asio::dynamic_buffer(stdOut), ec); if (stdOutLength > 0) { if (stdOut.size() != stdOutLength) stdOut.resize(stdOutLength); std::cout << stdOut; std::cout.flush(); } if (ec.value() != boost::system::errc::success) { std::cout << "------------------------\n" << "Pipe end.\n" << "eof: " << (ec == boost::asio::error::eof) << "\n" // Windows: 0, Linux: 1 << "error code: " << ec.value() << "\n" // Windows: 109, Linux: 2 << "error message: " << ec.message() << "\n" // Windows: "The pipe has been ended", Linux: "End of file" << "pipe is still open: " << stdOutPipe.is_open() << "\n" // Windows: 1, Linux: 1 << "process is still running: " << process.running() << "\n"; // Unreliable because the child process may crash or be terminated at any time, but got this: Windows: false, Linux: true std::cout.flush(); break; } } }); ctx.run(); int resultCode = process.wait(); return resultCode; }
Read Entire Article