简体   繁体   中英

boost::asio::async_read 100% CPU usage on simple example

In boost::asio standard examples after async_accept() the socket object is moving to the session object (which handles all async_read() calls) by initializing it as following:

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

And when constructing a session it's moving again (isn't it reduntantly?):

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

Then reading from a client is done as following:

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

And all goes well. But when I trying to make async_read() not from the session object but directly from the async_accept() and use it's socket object, CPU is raising to 100% immediately after client connects. Why?

#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();
}

Boost 1.49

EDIT

Thanks for the answers! I ended up by moving socket_ before using it:

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

Also the same problem is discussed at Repeated std::move on an boost::asio socket object in C++11

If the peer socket passed to basic_socket_acceptor::async_accept() is not open, then it will be opened during the async_accept() operation. Otherwise, if the peer is already open, then handler will be posted into the io_service for invocation with an error code of boost::asio::error::already_open . Hence, the posted code causes a tight asynchronous call chain to form:

  1. The async_accept() operation is invoked the first time, causing socket_ to be opened.
  2. The async_accept() handler invokes do_accept() , initiating an async_accept() operation.
  3. socket_ is already open, causing the async_accept() operation to post its handler into the io_service with an error of boost::asio::error::already_open .
  4. The asynchronous call chain starts back at step 2.

This behavior is not observed in the official examples because the socket's move operator causes the the moved-from object to be in the same state as if it was constructed using basic_stream_socket(io_service&) constructor. Thus, the moved-from object is in a closed state, and ready for accepting.

You're using the single socket_ in all places, so when a connection is accepted, your handler calls do_accept() again which is using the same socket_ , then it's accepted again and again...

You probably need to always use a new socket like below:

  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();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM