【问题标题】:Boost asio messes with standard input?Boost asio 与标准输入混淆?
【发布时间】:2017-02-28 10:00:31
【问题描述】:

此程序从标准输入(通过 iostream)读取并写入标准输出(通过 boost/asio):

#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <string>

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor out(io_service, ::dup(STDOUT_FILENO));
std::string line = "";

static void handler(
    boost::system::error_code const &,
    std::size_t
) {
    assert(std::getline(std::cin, line));
    line += "\n";
    async_write(out, boost::asio::buffer(line), handler);
}

int main()
{
    async_write(out, boost::asio::buffer(line), handler);
    io_service.run();
}

构建:g++ -std=gnu++1y -O0 -g3 -o out in.cxx -lboost_system -lboost_thread

运行:cat | ./out

输出:

foo [TERMINAL INPUT]
foo
bar [TERMINAL INPUT]
cat: -: Resource temporarily unavailable
bar
out: in.cxx:14: void handler(const boost::system::error_code&, std::size_t): Assertion `std::getline(std::cin, line)' failed.
Aborted (core dumped)

catwrite() 获取EAGAIN 到其标准输出,将其视为错误并关闭管道。反过来,getline() 失败,程序中止。

这看起来像 asio 正在将程序的标准输入(这是 cat 的标准输出,参见 Strange exception throw - assign: Operation not permitted)设置为非阻塞。它没有明显的理由这样做,因为它只在标准输出上运行。

如果我做对了,这是 asio 中的错误吗?有解决办法吗?

libboost1.58-dev/xenial-updates,now 1.58.0+dfsg-5ubuntu3.1 amd64 [installed]
g++/xenial,now 4:5.3.1-1ubuntu1 amd64 [installed]

【问题讨论】:

  • 我不知道你是如何推断“asio 正在将程序的标准输入设置为非阻塞”的。我看不出这种逻辑。是的,如果你将程序的输出重定向到一个文件,那么你会得到assign: operation not permitted,因为 linux 上的文件不支持 async-IO。
  • @sehe: cat-: Resource temporarily unavailable - 所以一定有人将文件描述符设置为非阻塞。如果不是cat或者shell,那一定是程序,即asio。
  • @sehe:我在这里没有看到 assign: operation not permitted 错误。我只提到我在哪里了解到 shell 管道的两端共享相同的文件描述符。
  • 哦。你应该说那个。此外,我看不到任何地方提出该声明(“外壳管道的两端共享相同的文件描述符”)。更重要的是,我认为这是错误的和无关紧要的。 (fds are local to a process anyways, there is no useful comparison between fds from different processes)
  • @sehe:嗯,这不是同一个文件描述符,但它们的文件描述符是指同一个打开的文件。因此,一个设置的标志(例如O_NONBLOCK)将被另一个看到。请参阅ideone.com/r4TVZd 的示例。

标签: c++ boost pipe boost-asio


【解决方案1】:

你在这里调用Undefined Behaviour

async_write(out, boost::asio::buffer(string + "\n"), handler);

由于缓冲区是一个局部变量,当handler 退出时,它将在异步写入操作有机会运行之前被销毁。

编辑实际上,即使变量不是本地变量,+ "\n" 也会使其成为临时变量!

以下是这个简单程序的建议修复:

Live On Coliru

#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <string>

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor out(io_service, ::dup(STDOUT_FILENO));
std::string input_buffer;

static void handler(boost::system::error_code /*error*/, std::size_t /*bytes_transferred*/) {
    if (std::getline(std::cin, input_buffer)) {
        input_buffer += "\n";
        async_write(out, boost::asio::buffer(input_buffer), handler);
    }
}

int main() {
    async_write(out, boost::asio::buffer(""), handler);
    io_service.run();
}

我不确定这是否能解决您的所有问题,但至少您需要修复它以便能够对您的程序进行推理

【讨论】:

  • 你是对的。但实际上它并不能解决问题,请参阅我的编辑。
猜你喜欢
  • 2011-02-19
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 1970-01-01
  • 2018-01-21
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多