使用 Boost.ASIO 读取时标准输入管道未关闭

stdin pipe not closing when read with Boost.ASIO

我正在使用 Boost.ASIO 读取标准输入,但是当我通过管道输入它时,我希望管道会在输入完全消耗后关闭。 IE。我在命令行执行此操作:

cat somefile.txt | myprog

而且我预计 myprog 会看到文件关闭。相反,它会永远等待。

代码如下所示:

boost::asio::posix::stream_descriptor as_stdin(ios);
{
    boost::system::error_code error;
    as_stdin.assign(dup(STDIN_FILENO), error);
    if ( error ) {
        exit(2);
    }
}
auto proc = [&as_stdinr](auto yield) {
        boost::asio::streambuf buffer;
        while ( as_stdin.is_open() ) {
            auto bytes = boost::asio::async_read_until(as_stdin, buffer, '\n', yield);
            if ( bytes ) {
                buffer.commit(bytes);
                std::istream in(&buffer);
                std::string line;
                std::getline(in, line);
                std::cerr << line << std::endl;
            } else {
                std::cerr << "No bytes read" << std::endl;
            }
        }
        std::cerr << "Done" << std::endl;
    };
boost::asio::spawn(ios, proc);

所有文件内容都被正确回显,因此从管道读取工作正常,但 "No bytes read" 或 "Done" 消息都没有被打印出来。我已经尝试过使用和不使用 dup 系统调用。

我是不是误解了管道的工作原理,还是我做错了什么或遗漏了什么?

我认为这归结为 "How do I detect EOF when using coroutines?"

您可以捕获来自 async_read_until

的异常
size_t bytes = 0;
bool eof = false;
try {
    bytes = boost::asio::async_read_until(as_stdin, buffer, '\n', yield);
} catch(std::exception const& e) {
    std::cerr << "Exception: " << e.what() << "\n";
    bytes = 0;
    eof = true;
}
// ...
if (eof) break;

或使用error_code:

boost::system::error_code ec;
auto bytes = boost::asio::async_read_until(as_stdin, buffer, '\n', yield[ec]);
// ...
if (ec) {
    std::cerr << "Error: " << ec.message() << "\n";
    break;
}

两种情况下的输出非常相似

Exception: End of file
No bytes read
Done

No bytes read
Error: End of file
Done

限制

常规文件不能与 POSIX stream_descriptor 一起使用,参见