[Signals] slot/trackable object disconnection question

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

On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
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.
This may very well be a bug; I'm currently swamped, but will be allocating some time to Signals in the next day or two. A few quick questions: 1) Which compiler are you using? 2) Which version of Boost are you using? Doug

On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
I have a question about the disconnection of slots in the signals
On Tue, 7 Sep 2004 13:49:02 -0500, Doug Gregor <dgregor@cs.indiana.edu> wrote: 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.
This may very well be a bug; I'm currently swamped,
Not a problem. I understand the feeling. =)
but will be allocating some time to Signals in the next day or two. A few quick questions: 1) Which compiler are you using? 2) Which version of Boost are you using?
For this project, I am using MSVC 6 SP6 and Boost 1.31.0. I also tried the latest 1.32 files for Signals from the CVS and saw the same behavior. Thanks, -Dave

On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
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?
Uh-oh.
Can someone please confirm if this behavior happens on other systems or if maybe there is some pecularity with my system/compiler?
Confirmed. There is clearly a bug here. Thanks for pointing this out and especially for distilling it down to a simple test case.
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?
I don't think that's the right solution, because watch_bound_objects gets copied around a bit, and would then disconnect too early. I'm revisiting this code now to try to isolate the bug. Doug

"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message news:D5FEB638-0DB1-11D9-A949-000D932B7224@cs.indiana.edu...
On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
...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?
I don't think that's the right solution, because watch_bound_objects gets copied around a bit, and would then disconnect too early. I'm revisiting this code now to try to isolate the bug.
I agree. After trying out that idea, I noticed exactly what you said. It did indeed cause slots to disconnect prematurely. However, what if you made watch_bound_objects a shared_ptr<connection> instead of a just a connection? In that case, you could still set it as controlling at the end of create_connection, but the connection wouldn't be destroyed unless all copies of the slot ceased to exist. It seems like that would work to clean up the slot/trackable references at the proper time, but maybe there is a more elegant solution than that. -Dave

On Sep 23, 2004, at 10:28 PM, Dave Deakins wrote:
"Doug Gregor" <dgregor@cs.indiana.edu> wrote in message news:D5FEB638-0DB1-11D9-A949-000D932B7224@cs.indiana.edu...
On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
...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?
I don't think that's the right solution, because watch_bound_objects gets copied around a bit, and would then disconnect too early. I'm revisiting this code now to try to isolate the bug.
I agree. After trying out that idea, I noticed exactly what you said. It did indeed cause slots to disconnect prematurely. However, what if you made watch_bound_objects a shared_ptr<connection> instead of a just a connection? In that case, you could still set it as controlling at the end of create_connection, but the connection wouldn't be destroyed unless all copies of the slot ceased to exist. It seems like that would work to clean up the slot/trackable references at the proper time, but maybe there is a more elegant solution than that.
-Dave
I'm sure there's a more elegant solution, but I'm a bit afraid to rock the boat with Aleksey trying to roll a release :) I'm going to give myself the evening to see if I can think up any problems with this solution, and will try to implement it within the next day or so. Thanks for your help! Let's hope this thing cleans up nicely :) Doug

On Sep 5, 2004, at 5:51 PM, Dave Deakins wrote:
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?
[snip]
The following program roughly illustrates the behaviour I see in my application:
I've now (finally!) fixed this bug in CVS. Thank you again for the bug report. Doug
participants (2)
-
Dave Deakins
-
Doug Gregor