用标准输入增强asio混乱?

时间:2017-02-28 10:00:31

标签: c++ boost pipe boost-asio

该程序从stdin读取(通过iostream)并写入stdout(通过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)

catEAGAIN获取write()到其标准输出,将其视为错误,然后关闭管道。反过来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]

1 个答案:

答案 0 :(得分: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();
}

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