【问题标题】:Strange exception throw - assign: Operation not permitted奇怪的异常抛出 - 分配:不允许操作
【发布时间】:2014-05-12 16:35:16
【问题描述】:

我想从 cin 进行异步读取,因此我有一段代码

client.h

...
boost::asio::posix::stream_descriptor input;
boost::asio::streambuf input_buffer

client.cpp

Client::Client(int argc, char **argv, boost::asio::io_service &io_service)
    : tcp_socket(io_service)
    , udp_socket(io_service)
    , input(io_service, ::dup(STDIN_FILENO))
{
    ...
    read_std_input();
}

void Client::read_std_input() {
    async_read_until(input, input_buffer, '\n',
                     boost::bind(&Client::handle_std_read, this,
                                 boost::asio::placeholders::error,
                                 boost::asio::placeholders::bytes_transferred));
}

问题是:当我以正常方式 [ ./client ] 运行我的客户端,然后通过类似命令输入一些内容时,它就像魅力一样工作。 但是,当我通过 [ ./client

在抛出一个实例后调用终止 'boost::exception_detail::clone_impl

'what():assign: Operation not allowed Aborted

您知道问题可能是什么吗? 谢谢!

【问题讨论】:

  • 你没有提到你使用的是什么平台。 Windows 和 Linux(以及 ....)对异步文件 I/O 的支持大不相同
  • 我使用的是 linux mint 16 64bit
  • 用 strace 看看系统调用可能会抱怨什么。
  • 你能提供你的内核配置吗?例如。 “启用 AIO 支持 (AIO)”等会很有趣

标签: c++ boost boost-asio


【解决方案1】:

Boost.Asio 的 POSIX 面向流的描述符明确不支持常规文件。因此,如果test 是一个常规文件,那么在尝试将STDIN_FILENO 分配给stream_descriptor 时,./client < test 将导致posix::stream_descriptor::assign() 失败。 documentation 声明:

Boost.Asio 包括添加的类以允许对 POSIX 文件描述符执行同步和异步读写操作,例如管道、标准输入和输出以及各种设备(但不是常规文件)。

考虑通过管道将test 文件的内容传递给client

$ cat test | ./client

这是一个完整的示例程序和演示:

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

void handle_read(
  const boost::system::error_code& error,
  std::size_t bytes_transferred
)
{
  std::cout << "read " << bytes_transferred << " bytes with "
            << error.message() << std::endl;
}

int main()
{
  boost::asio::io_service io_service;
  boost::asio::posix::stream_descriptor input(io_service);

  // Assign STDIN_FILENO to the stream_descriptor.  It will support
  // pipes, standard input and output, and various devices, but NOT
  // regular files.
  boost::system::error_code error;
  input.assign(STDIN_FILENO, error);
  if (error)
  {
    std::cerr << error.message() << std::endl;
    return -1;
  }

  boost::asio::streambuf input_buffer;
  async_read_until(input, input_buffer, '\n', &handle_read);
  io_service.run();
}

示范

$ ./客户 测试标准输入进入 成功读取 23 个字节 $ echo "这是一个测试" > 测试 $ ./client

【讨论】:

  • 非常感谢,它解释了一切!
【解决方案2】:

Boost asio 在 Linux 上使用 epoll 系统 by default 其中 does not support files

但有一个解决方法:如果您定义 BOOST_ASIO_DISABLE_EPOLL,那么 asio 将恢复为 select 系统并且文件将起作用。

【讨论】:

    【解决方案3】:

    Linux 上的异​​步文件 I/O 仍然相当原始。尽管 ASIO 对异步文件 I/O 的支持在 Windows 中运行良好,但我在 Linux 上使用它并没有太多(……呃任何)运气。

    This is a previous SO question that provides some background on the issue.

    【讨论】:

      【解决方案4】:

      你能试试这个最小的复制器吗?它适用于我的 Ubuntu 64 位机器:

      #include <boost/asio.hpp>
      #include <boost/asio/posix/stream_descriptor.hpp>
      
      #include <iostream>
      
      int main()
      {
          using namespace boost::asio;
      
          io_service io;
          posix::stream_descriptor input(io);
      
          input.assign(STDIN_FILENO);
          streambuf input_buffer;
      
          std::function<void()> loop = [&] {
              async_read_until(input, input_buffer, '\n', [&](boost::system::error_code ec, size_t) {
                  if (ec) 
                      std::cerr << ec.message();
                  else {
                      std::cout << "LOOP: '" << &input_buffer << "'\n";
                      loop();
                  }
              });
          };
      
          loop();
          io.run();
      }
      

      更新我想我可以重现问题on Coliru:你能检查ulimit -a的输出吗?

      【讨论】:

      • 此代码在将文件传递给 i/o 时也会抛出。这是 ulimit -a 的输出:pastebin.com/WfpNkGjV
      猜你喜欢
      • 2013-02-09
      • 2017-11-05
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多