boost::process
允许以可移植的方式将程序输出重定向到管道,因此不需要使用预处理器条件并调用OS特定的API来运行进程,创建和读取管道。
boost::process
支持同步和异步IO。同步会产生高的死锁风险;根据我的经验,如果应用程序很复杂,并且运行着许多带有不同输出的子代(类似于旧的好CGI
协议实现,例如,我们运行未知且可能是第三方的,有问题的子代进程),则< strong>保证,boost::process
同步IO迟早会导致死锁。
因此,我们必须使用基于boost::asio
的异步IO。它可以帮助我们避免陷入僵局,但是,它会提出更多没有答案的问题。
通常,我们要读取child生成的所有数据。我们也通常不知道子级将生成多少数据,它将不会生成任何数据,是否会崩溃,预期的数据格式等等。我们通常一无所知,并且仍然希望读取所有数据。即使进程错误代码非零,它仍然可以打印我们也要阅读的任何有用的错误消息。
我看到的唯一方法是读取直到出现错误。当我们将boost::asio
与TCP套接字一起使用时,当套接字关闭时,它将引发文件结尾错误,因此我们可以知道它是数据结尾,并且套接字已关闭,因此不会再显示任何数据。
但是,对于async_pipe
,没有记录错误代码必须表示end of pipe
或pipe is closed by other side
的含义。
在实践中,我们可以使用以下代码“读取直到出错”:
std::vector<char> exec(const std::string & command)
{
using boost::asio::async_read;
using boost::asio::buffer;
using boost::asio::io_context;
using boost::system::error_code;
using boost::system::system_error;
using namespace std;
namespace bp = boost::process;
io_context async_io_context;
bp::async_pipe command_stdout(async_io_context);
bp::child command_process(command, bp::std_in.close(), bp::std_out > command_stdout, bp::std_err > command_stdout, bp::shell);
static constexpr const size_t kStdOutBufferSize = 65535;
array<char, kStdOutBufferSize> command_stdout_buffer;
vector<char> command_output;
function<void(const boost::system::error_code &ec, std::size_t size)> async_read_handler_function;
error_code io_error_code;
async_read_handler_function = [&](const error_code &ec, std::size_t size)
{
// Write data
if(size)
command_output.insert(command_output.end(), command_stdout_buffer.data(), command_stdout_buffer.data() + size);
// Parse error code
if (ec)
{
io_error_code = ec;
async_io_context.stop();
}
else
async_read(command_stdout, buffer(command_stdout_buffer.data(), command_stdout_buffer.size()), async_read_handler_function);
};
async_read(command_stdout, buffer(command_stdout_buffer.data(), command_stdout_buffer.size()), async_read_handler_function);
async_io_context.run();
if (io_error_code)
{
// TODO: so how to make us sure that we really read all data and other side of pipe is gracefully closed by child process?
}
return command_output;
}
在Windows上,当一切正常运行时,此代码实际上会读取所有输出并返回带有system_category
和109
整数值的错误代码。在boost
错误代码枚举中,109
表示boost::system::errc::destination_address_required
。我的问题:
boost::system::errc::destination_address_required
?如果代码不可移植,并且其他操作系统上的错误也会有所不同,那么使代码可移植的方法是什么? boost
如果仅创建可移植代码,则具有意义,否则系统特定的API更好,因为它们将提供更好的性能和对系统特定功能的更深入的使用。