trying to understand boost example httpserver3. Something unclear with shared_ptr reset method

StackOverflow https://stackoverflow.com/questions/18805258

Question

I'm working with boost example httpserver3 : http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html#boost_asio.examples.http_server_3

I can't clearly understand what happens when the reset method of new_connection_ is called

void server::start_accept()
{
  new_connection_.reset(new connection(io_service_, request_handler_));
  acceptor_.async_accept(new_connection_->socket(),
      boost::bind(&server::handle_accept, this,
        boost::asio::placeholders::error));
}

void server::handle_accept(const boost::system::error_code& e)
{
  if (!e)
  {
    new_connection_->start();
  }
    std::cout<<"handle_accept"<<std::endl;
  start_accept();
}

I know that "reset" will cause the previous object to be deleted as the documentation says. what happens if the server object accepts a new connection while previous connection object is handling it's request? will the previous connection be destroyed immediately or it will receive an error and exits?

void connection::handle_read(const boost::system::error_code& e,
    std::size_t bytes_transferred)
{
  if (!e)
  {
    boost::tribool result;
    boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
        request_, buffer_.data(), buffer_.data() + bytes_transferred);

    if (result)
    {
      request_handler_.handle_request(request_, reply_);
      boost::asio::async_write(socket_, reply_.to_buffers(),
          strand_.wrap(
            boost::bind(&connection::handle_write, shared_from_this(),
              boost::asio::placeholders::error)));
    }
    else if (!result)
    {
      reply_ = reply::stock_reply(reply::bad_request);
      boost::asio::async_write(socket_, reply_.to_buffers(),
          strand_.wrap(
            boost::bind(&connection::handle_write, shared_from_this(),
              boost::asio::placeholders::error)));
    }
    else
    {
      socket_.async_read_some(boost::asio::buffer(buffer_),
          strand_.wrap(
            boost::bind(&connection::handle_read, shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred)));
    }
  }

  // If an error occurs then no new asynchronous operations are started. This
  // means that all shared_ptr references to the connection object will
  // disappear and the object will be destroyed automatically after this
  // handler returns. The connection class's destructor closes the socket.
}

void connection::handle_write(const boost::system::error_code& e)
{
  if (!e)
  {
    // Initiate graceful connection closure.
    boost::system::error_code ignored_ec;
    socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
  }

  // No new asynchronous operations are started. This means that all shared_ptr
  // references to the connection object will disappear and the object will be
  // destroyed automatically after this handler returns. The connection class's
  // destructor closes the socket.
} 
Était-ce utile?

La solution

Ah, the magic of shared_from_this(). You've missed this part of the code:

void connection::start()
{
  socket_.async_read_some(boost::asio::buffer(buffer_),
      strand_.wrap(
        boost::bind(&connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred)));
}

What happens is this:

  1. server::handle_accept() calls new_connection_->start().
  2. connection::start() schedules a read operation, and by doing this, creates a copy of the original shared pointer with the shared_from_this() call.
  3. Now server::handle_accept() calls server::start_accept().
  4. server::start_accept() does reset() the original shared pointer, but the ASIO service has a copy of it, so as long as connection's callbacks keep scheduling more operations using shared_from_this(), the connection won't be destroyed (because there'll be at least one shared pointer still pointing to the heap-allocated connection object).
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top