【问题标题】:boost::asio::async_read 100% CPU usage on simple exampleboost::asio::async_read 简单示例中的 100% CPU 使用率
【发布时间】:2014-01-06 02:04:39
【问题描述】:

在 boost::asio standard examples async_accept() 之后,socket 对象通过如下初始化移动到 session 对象(处理所有 async_read() 调用):

std::make_shared<session>(std::move(socket_))->start();

当构造一个session 时,它又在移动(不是很重复吗?):

session(tcp::socket socket)
  : socket_(std::move(socket))

然后从客户端读取如下:

boost::asio::async_read(socket_, ...

一切顺利。但是,当我尝试不是从 session 对象而是直接从 async_accept() 生成 async_read() 并使用它的 socket 对象时,CPU 在客户端连接后立即提升到 100%。为什么?

#include <boost/asio.hpp>
using boost::asio::ip::tcp;

class Server
{
public:
  Server(boost::asio::io_service& io_service,
         const tcp::endpoint& endpoint)    
    : acceptor_(io_service, endpoint),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
       [this](boost::system::error_code ec)
       {
         if (!ec) {
           char* buf = new char[5];
           boost::asio::async_read(socket_,
              boost::asio::buffer(buf, 5),
              [this, buf](boost::system::error_code ec, std::size_t)
              {
                if (!ec) {
                  std::cout.write(buf, 5);
                  std::cout << std::endl;
                }
                delete[] buf;
              });
         }
         do_accept();
       });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
};

int main(int argc, char* argv[])
{
  int port = 22222;
  boost::asio::io_service io_service;
  tcp::endpoint endpoint(tcp::v4(), port);
  new Server(io_service, endpoint);
  io_service.run();
}

提升 1.49

编辑

感谢您的回答!我最终在使用之前移动了socket_

tcp::socket *socket = new tcp::socket(std::move(socket_));

Repeated std::move on an boost::asio socket object in C++11也讨论了同样的问题

【问题讨论】:

    标签: c++ sockets networking boost boost-asio


    【解决方案1】:

    您在所有地方都使用单个socket_,因此当连接被接受时,您的处理程序再次调用使用相同socket_ 的do_accept(),然后它一次又一次地被接受...

    您可能需要始终使用如下所示的新套接字:

      void do_accept()
      {
        boost::shared_ptr<tcp::socket> psocket(new tcp::socket(io_service));
        acceptor_.async_accept(*psocket, boost::bind(&Server::handleAccept, this, psocket, _1));
      }
    
      void handleAccept(boost::shared_ptr<tcp::socket> psocket, const boost::system::error_code& ec)
      {
        if (!ec) {
        char* buf = new char[5];
        boost::asio::async_read(
          *psocket,
          boost::asio::buffer(buf, 5),
          [this, buf](boost::system::error_code ec, std::size_t)
          {
            if (!ec) {
              std::cout.write(buf, 5);
              std::cout << std::endl;
            }
            delete[] buf;
          });
        }
        do_accept();
      }
    

    【讨论】:

      【解决方案2】:

      如果传递给basic_socket_acceptor::async_accept()peer 套接字未打开,那么它将在async_accept() 操作期间打开。否则,如果 peer 已经打开,则 handler 将被发送到io_service 以进行调用,错误代码为boost::asio::error::already_open。因此,发布的代码会导致形成紧密的异步调用链:

      1. async_accept() 操作第一次被调用,导致socket_ 被打开。
      2. async_accept() 处理程序调用do_accept(),启动async_accept() 操作。
      3. socket_ 已经打开,导致async_accept() 操作将其处理程序发布到io_service 中,错误为boost::asio::error::already_open
      4. 异步调用链从第 2 步开始。

      在官方示例中未观察到此行为,因为socket's move operator 导致被移动对象处于与使用basic_stream_socket(io_service&amp;) 构造函数构造时相同的状态。因此,被移出的对象处于关闭状态,并准备好接受。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-30
        • 1970-01-01
        • 1970-01-01
        • 2013-02-24
        • 2013-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多