Boost logo

Boost :

From: Dave Deakins (ddeakins_at_[hidden])
Date: 2004-09-05 17:51:46


I have a question about the disconnection of slots in the signals library.
I couldn't find any information about it in previous message threads, but if
I missed one you guys can just direct me to the appropriate discussion.

In my project I have a serial port communications queue that allows various
other objects to transmit a command over the serial port and then have the
response routed to a designated callback function. Each command request can
specify a different response callback function and often the object posting
the command will ask the queue to pass the response data back to one of its
member functions for interpretation. I use the automated connection
management feature of signals to insure that the response member function is
not called if its target object is destroyed before the serial port response
is received. This queue typically handles about 10-15 command/response
transactions per second and I noticed that, after about 15-20 hours of
continuous operation, the system began to run low on available memory. I
spent a fair amount of time trying to track down the source of the excessive
memory usage and it appeared that it was coming from the trackable object
base class.

Each time a command is added to the communications queue, a new queue entry
is created and we connect the response handling function to the signal in
this queue entry. If I understand correctly, signal's connect function will
create a temporary slot object to adapt the
boost::bind(&AClass::ResponseFunction, pAClass, _1, _2) object that is
passed to it. When this temporary slot is created, it uses visit_each to
enumerate the bound trackable objects and then uses
trackable::signal_connected(...) to have each bound trackable object save a
'controlling' connection to the slot in its connected_signals list. So if
any of the bound trackable objects are destroyed, the 'controlling'
connection will deactivate the slot and tell all of the bound trackable
objects used by the slot that they can erase their connections to this slot.

So my question is this: When a slot object (not a signal object) is
destroyed, what tells the trackable objects that are used by the slot that
they can release their connection to this slot?

Signal objects make the connections in their internal slot map 'controlling'
so these connections would do the clean up when the signal is destroyed. As
mentioned above, trackable objects also make the connections in their
internal connected_signals list 'controlling' to enable deactivation and
clean up of standalone slots or slots connected to signals when the
trackable object is destroyed. But the watch_bound_objects connection in
the slot object is not 'controlling' (as far as I can tell) and thus a slot
does not seem to have any way to indicate to the bound objects that this
connection needs to be cleaned up if the slot is destroyed.

The following program roughly illustrates the behaviour I see in my
application:

#include "boost\bind.hpp"
#include "boost\signals.hpp"

class CommunicatingObject : public boost::signals::trackable {

 public:
    void ProcessResponse() {}
};

int main(int argc, char* argv[])
{
   CommunicatingObject Obj;
   while (true) {

      boost::signal0<void> NewResponseData;
      NewResponseData.connect(
boost::bind(&CommunicatingObject::ProcessResponse, &Obj) );

      NewResponseData();
   }

   return 0;
}

Obj would represent the object making a request on the queue and
NewResponseData would represent the signal contained in the queue entry.
When I run this test program on my system, the system runs out of memory in
fairly short order. I have the same memory draining situation if the
while(true) loop is changed to the simpler case of:

   while (true) {

      boost::signal0<void>::slot_type(
boost::bind(&CommunicatingObject::ProcessResponse, &Obj) );
   }

Can someone please confirm if this behavior happens on other systems or if
maybe there is some pecularity with my system/compiler? If this situation
is not peculiar to my system, should there be a:

   watch_bound_objects.set_controlling();

statement at the very end of the slot_base::create_connection() procedure
(after the safe_connection.release() statement) in slot.cpp?

Thanks in advance for your help,
-Dave


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk