Discussion:
[asio-users] Server examples: connection destruction
Dale Wilson
2012-11-08 22:36:24 UTC
Permalink
void server::handle_accept(const boost::system::error_code& e)
{
  if (!e)
  {
// Start first connection
    new_connection_->start();
// Create second connection
    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));
  }
}
The problem is: the "second" connection is constructed but never
destroyed; i.e. when io_service_.stop() is called, the thread exits
properly but the destructor of the second connection is never called.
I have verified this by placing debug statements in the destructor.
What do I need to do to get the destructor of the second (non-started)
connection to be called when io_service_.stop() is called?
Either call
new_connection_.reset();
after io_service.stop();

Or don't worry about it. The second object will be destroyed when your server
object is destroyed.

Dale
Gruenke, Matt
2012-11-08 22:36:57 UTC
Permalink
new_connection_ is a shared_ptr<> and a member of server? Well, it should get destroyed when last copy of the second new_connection_ is reset - either when you explicitly call new_connection_.reset() or when that server is destroyed.

In a related, but different case, remember that when you bind a shared_ptr<> to compose a completion handler, the resulting function object holds a reference. So, to whatever the completion handler is passed now holds a reference, as well. Simply calling stop() on a io_service doesn't cancel any of these operations. Therefore, any async ops you've initiated will still be around and will hold references via the completion handlers they've been passed.

shared_ptr<> and boost::bind<>() are powerful tools to help YOU manage object lifetimes. But you still need to be aware of what's holding a refcount on what. It is not general-purpose garbage collection, and you'll get burned if you treat it that way. I know that's not what you were asking, but this is an important point that I think deserves an occasional reminder.


Matt


-----Original Message-----
From: barcaroller [mailto:***@gmail.com]
Sent: November 08, 2012 17:18
To: asio-***@lists.sourceforge.net
Subject: [asio-users] Server examples: connection destruction

In the ASIO server examples, the author uses the following constructs:

void server::handle_accept(const boost::system::error_code& e)
{
  if (!e)
  {
// Start first connection
    new_connection_->start();

// Create second connection
    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));
  }
}


The problem is: the "second" connection is constructed but never destroyed; i.e. when io_service_.stop() is called, the thread exits properly but the destructor of the second connection is never called.
I have verified this by placing debug statements in the destructor.

What do I need to do to get the destructor of the second (non-started) connection to be called when io_service_.stop() is called?



------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_nov
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio
Gruenke, Matt
2012-11-09 00:46:20 UTC
Permalink
It's not a bug in ASIO. It's just a way to tell the io_service threads
to return before finishing the rest of the pending work. The bug is
that you were treating it as though it cancelled all outstanding
operations involving that io_service, which is not what the docs say it
does.


http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_s
ervice/stop.html


I don't use io_service::stop(), in my programs. Not for shutdown,
anyhow. The model I prefer is to stop all of the individual state
machines, explicitly remove the work, and then let the io_service
thread(s) return when all of that has been completed.

An approach closer to what you probably had in mind is to call stop,
wait for the threads to return, destroy the individual objects using the
io_service, then destroy the actual io_service. I believe this is safe
and won't leak anything, but I'm not speaking from experience. The
biggest practical difference is that my approach doesn't violate the
guarantee that completion handlers will always be called, whereas I
think this one will (or at least which thread is calling them & the
state of your program at the point where they're called). Either way,
it will be one more thing to keep in mind, as you write your handlers.


Matt


-----Original Message-----
From: barcaroller [mailto:***@gmail.com]
Sent: November 08, 2012 17:51
To: asio-***@lists.sourceforge.net
Subject: Re: [asio-users] Server examples: connection destruction
Post by Dale Wilson
Either call
new_connection_.reset();
after io_service.stop();
Or don't worry about it. The second object will be destroyed when
your server object is destroyed.
Dale
Thank you for your quick response. I can't call
new_connection_.reset() after io_service.stop() because the io_service
object is in a different module that knows nothing about the individual
connections (I refer you to the HTTP 3 server example). The reason why
I think that this is a bug in ASIO is that when io_service.stop() is
called, it properly shuts down all the threads and calls the destructor
of all connections except the last one (the one that was constructed but
never started).

That is a valid point, but I have to worry about it because I depend on
the connection destructor to do important clean-up. If one destructor
is missed, the cleanup cannot be completed.



------------------------------------------------------------------------
------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics Download AppDynamics Lite for
free today:
http://p.sf.net/sfu/appdyn_d2d_nov
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio
Yuri Timenkov
2012-11-09 05:28:45 UTC
Permalink
That's exactly reason not to use stop().

Personally I discourage it's use in our code because it leads to exactly
these resource leaks (of course unless you know exactly what you're doing).
Instead of thinking why io_service doesn't stop people tend to go with this
easiest solution which looks like working but really isn't.

It's much much better to initiate shutdown (close sockets, destroy
io_service::work objects, etc.) and wait until io_service runs out of work
by itself.
Post by Gruenke, Matt
It's not a bug in ASIO. It's just a way to tell the io_service threads
to return before finishing the rest of the pending work. The bug is
that you were treating it as though it cancelled all outstanding
operations involving that io_service, which is not what the docs say it
does.
http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_s
ervice/stop.html
I don't use io_service::stop(), in my programs. Not for shutdown,
anyhow. The model I prefer is to stop all of the individual state
machines, explicitly remove the work, and then let the io_service
thread(s) return when all of that has been completed.
An approach closer to what you probably had in mind is to call stop,
wait for the threads to return, destroy the individual objects using the
io_service, then destroy the actual io_service. I believe this is safe
and won't leak anything, but I'm not speaking from experience. The
biggest practical difference is that my approach doesn't violate the
guarantee that completion handlers will always be called, whereas I
think this one will (or at least which thread is calling them & the
state of your program at the point where they're called). Either way,
it will be one more thing to keep in mind, as you write your handlers.
Matt
-----Original Message-----
Sent: November 08, 2012 17:51
Subject: Re: [asio-users] Server examples: connection destruction
Post by Dale Wilson
Either call
new_connection_.reset();
after io_service.stop();
Or don't worry about it. The second object will be destroyed when
your server object is destroyed.
Dale
Thank you for your quick response. I can't call
new_connection_.reset() after io_service.stop() because the io_service
object is in a different module that knows nothing about the individual
connections (I refer you to the HTTP 3 server example). The reason why
I think that this is a bug in ASIO is that when io_service.stop() is
called, it properly shuts down all the threads and calls the destructor
of all connections except the last one (the one that was constructed but
never started).
That is a valid point, but I have to worry about it because I depend on
the connection destructor to do important clean-up. If one destructor
is missed, the cleanup cannot be completed.
------------------------------------------------------------------------
------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics Download AppDynamics Lite for
http://p.sf.net/sfu/appdyn_d2d_nov
_______________________________________________
asio-users mailing list
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
http://p.sf.net/sfu/appdyn_d2d_nov
_______________________________________________
asio-users mailing list
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio
Loading...