0

I am using Boost asio to open several sockets I use a collection with shared pointers to a custom class with all that socket info. This class also has the handle_read function for async_receive as I need to do different things with each receive and I can not bind with extra parameters.

The problem I am having is that when I close the socket I delete the last reference to that pointer so the handle_read function is called without any valid reference as this and then the code just breaks.

void SocketsAPI::do_close(const SocketInfo socket)
{
    log("do_close");
    if (!socket.m_socket || !socket.m_socket->is_open()) {
        return;
    }   
    boost::system::error_code errorcode;
    socket.m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
    if (errorcode) {
        trace("Closing failed: ", errorcode.message());
    }
    socket.m_socket->close(errorcode);
    if (errorcode) {
        trace("Closing2 failed: ", errorcode.message());
    }
    mapType::iterator iter = sockets.find(socket.key);
    if (iter != sockets.end()) {
        sockets.erase (iter);
    }
    log("do_close end");
}

Indeed I don't want the handle_read function to be called but I am unable to avoid it, and what it is worse in a multithreaded implementation (several threads calling io_service.run()) the handle_read will be called while the close is still being processed so "this" object will be freed in any point of the handler.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
frisco
  • 1,897
  • 2
  • 21
  • 29

1 Answers1

2

It sounds like you are close but haven't quite understood the shared ownership semantics that are typically done with applications using the Boost.Asio asynchronous methods. You will want to use shared_from_this() when binding your callback handlers to ensure they remain in scope for the duration of the async operation. The io_service::~io_service() documentation explains this quite nicely.

When you need to stop the async operation prematurely, cancel it rather than closing the socket in your SocketsAPI::do_close() method. Then your callback will be given an error code of boost::asio::error::operation_aborted which you can use to react appropriately.


the handle_read will be called while the close is still being processed so "this" object will be freed in any point of the handler.

This is really a separate question, you need to use strands to ensure exclusive access to data structures within a handler callback.

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • Thanks for the solution it is my first take with Asio and it seems that is really difficult to master. Using shared_from_this works perfectly while using a thread pool I still get a crash while using only 1 thread but probably that is not related the original problem. – frisco Mar 19 '13 at 12:56
  • @frisco feel free to ask another question – Sam Miller Mar 19 '13 at 14:25
  • the problem is that I am unsure about what is the question :D I am getting a "Microsoft C++ exception: boost::exception_detail::clone_impl > at memory location 0x0672f4bc.." but I am not sure when is triggered and VS Debugging isn't helping either. – frisco Mar 19 '13 at 14:59
  • @frisco if you tag the question with [tag:visual-c++] and [tag:boost] I'm sure someone will be able to help. – Sam Miller Mar 19 '13 at 20:40