Mixing signals2 and asio mechanism failing

I've the following: <1> a single instance of io_service object with a program life-time and several threads calling it's run() method. io_service::work is given to it so that it never terminates (unless we stop it). <2> class A which has boost::signals2::signal connecting functions for callback. * async operations (eg., async_read_until, async_write etc) <3> class B which is derived from std::shared_from_this ; * has a composition of class A as std::unique_ptr which is instantiated in B's constructor ; <c> has functions/listeners which are registered with signals of class A (eg., signals2::connection connectionObj = uniqPtrA->someSig.connect([=]{shared_from_this_ptrB->listenerFuncOfB();}); <4> Another thread outside the thread-pool of <1> above which instantiates (and manages) class B: auto ptrB = std::make_shared(); //and further operations. The problem is when I need to destroy ptrB I can't. For instance, i call some method of class B on ptrB to clear all connections it has with class A and allow ptrB to go out of scope, but class B destructor is never called: {//local scope auto ptrB = std::make_shared(); ptrB->connectListenersToA(); /* eg auto self = shared_from_this(); connectionObj = uniqPtrA->someSig.connect([=]{self ->listenerFuncOfB();}); referring to <3> above */ //... do some operations ptrB->disconnectListenersWithA(); //eg connectionObj.disconnect(); referring to <3> above }//Scope ends I want ptrB to destroy the underlying pointer. The ptrB destructor is never called because signals2::connection::disconnect does not seem to wipe out the given slot so the shared_ptr reference of B remains with the signal in class A as anonymous functor (due to lambda in <3> above) containing it does not get destroyed. How do I achieve this? -- View this message in context: http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... Sent from the Boost - Users mailing list archive at Nabble.com.

On Sat, Oct 19, 2013 at 5:46 PM, ustulation
The ptrB destructor is never called because signals2::connection::disconnect does not seem to wipe out the given slot so the shared_ptr reference of B remains with the signal in class A as anonymous functor (due to lambda in <3> above) containing it does not get destroyed.
The signal does destroy the slot eventually, though not immediately in the disconnect call as you have noted. There is a ticket to change this behavior, as people seem to find it surprising: https://svn.boost.org/trac/boost/ticket/8533 -- Frank

:) I feel somewhat intimidated talking to developers of world-renowned libraries themselves - what might be difficult for me might be so trivial for you; but anyway here's the question - So since the things are the way they are how do I achieve a thread safe clean-up? This is what it is: { io_service::run is called by many threads and classes use enable_shared_from_this idiom } class A { /* has signals2::signal(s) for callbacks, fired when completion-handler of various async operations are invoked (eg., async_read_until etc) */ }; class B { void registerListenersWith_A() { /* has member-function listeners submitted to signals of class A eg., auto self = shared_from_this(); shared_ptr_A->someSig_A.connect([self]{self->mem_func_B();}); */ } void disconnectListenersWith_A() { /* disconnect all boost::signals2::connection(s) made above */ } }; auto shared_ptr_A = std::make_shared< A >(); { auto shared_ptr_B = std::make_shared< B >(); give shared_ptr_B a copy of shared_ptr_A for use above. shared_ptr_B->registerListenersWith_A(); //....some operations here..... shared_ptr_B->disconnectListenersWith_A(); } //i want pointer managed by shared_ptr_B to be destroyed here in a thread-safe manner (ie., no pending calls remain from A to B etc. -- View this message in context: http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... Sent from the Boost - Users mailing list archive at Nabble.com.

On Sun, Oct 20, 2013 at 3:37 AM, ustulation
class A { /* has signals2::signal(s) for callbacks, fired when completion-handler of various async operations are invoked (eg., async_read_until etc) */ };
class B { void registerListenersWith_A() { /* has member-function listeners submitted to signals of class A eg., auto self = shared_from_this(); shared_ptr_A->someSig_A.connect([self]{self->mem_func_B();}); */ } void disconnectListenersWith_A() { /* disconnect all boost::signals2::connection(s) made above */ } };
auto shared_ptr_A = std::make_shared< A >(); { auto shared_ptr_B = std::make_shared< B >(); give shared_ptr_B a copy of shared_ptr_A for use above. shared_ptr_B->registerListenersWith_A(); //....some operations here..... shared_ptr_B->disconnectListenersWith_A(); } //i want pointer managed by shared_ptr_B to be destroyed here in a thread-safe manner (ie., no pending calls remain from A to B etc.
I'd think about using weak_ptr to break your cyclic shared_ptr object ownership between class A and B. Also, you can use the track() method on slots to auto-disconnect the member function of class B when it's last owning shared_ptr expires, rather than binding a shared_ptr into the slot. track() will also prevent the class B object from being destroyed mid-invocation by creating a temporary shared_ptr. That said, as long as you manually call disconnect at some point, the disconnected slots in the signal will eventually be destroyed during cleanup, either in a later signal::connect call, a later signal invocation, or on signal destruction.

I see. I think I will look more into weak_ptr/track() methods to achieve what I want because I might land up having shared_ptr< A > being a composition inside B and then in event of no further interaction with A's signal they would both exist for the lifetime of the program. I'd posted a query here too: http://stackoverflow.com/questions/19476578/mixing-boostasio-and-boostsignal... In the hack there I have assumed that signals make a copy of slots before executing them and hence that hack would work -> it would delete the actual functor when connecting dummy() and then the copy once slot() returns (assuming that the signal had been fired and the control was inside slot() when stop() was called). Is that assumption correct (about copying the list of slots before executing them) ? I got it from: http://stackoverflow.com/a/4490785/1060004 On Sun, Oct 20, 2013 at 8:22 PM, Frank Mori Hess-3 [via Boost] < ml-node+s2283326n4653403h91@n4.nabble.com> wrote:
On Sun, Oct 20, 2013 at 3:37 AM, ustulation <[hidden email]http://user/SendEmail.jtp?type=node&node=4653403&i=0
wrote:
class A { /* has signals2::signal(s) for callbacks, fired when completion-handler of various async operations are invoked (eg., async_read_until etc) */ };
class B { void registerListenersWith_A() { /* has member-function listeners submitted to signals of class A eg., auto self = shared_from_this(); shared_ptr_A->someSig_A.connect([self]{self->mem_func_B();}); */ } void disconnectListenersWith_A() { /* disconnect all boost::signals2::connection(s) made above */ } };
auto shared_ptr_A = std::make_shared< A >(); { auto shared_ptr_B = std::make_shared< B >(); give shared_ptr_B a copy of shared_ptr_A for use above. shared_ptr_B->registerListenersWith_A(); //....some operations here..... shared_ptr_B->disconnectListenersWith_A(); } //i want pointer managed by shared_ptr_B to be destroyed here in a thread-safe manner (ie., no pending calls remain from A to B etc.
I'd think about using weak_ptr to break your cyclic shared_ptr object ownership between class A and B. Also, you can use the track() method on slots to auto-disconnect the member function of class B when it's last owning shared_ptr expires, rather than binding a shared_ptr into the slot. track() will also prevent the class B object from being destroyed mid-invocation by creating a temporary shared_ptr.
That said, as long as you manually call disconnect at some point, the disconnected slots in the signal will eventually be destroyed during cleanup, either in a later signal::connect call, a later signal invocation, or on signal destruction.
_______________________________________________ Boost-users mailing list [hidden email] http://user/SendEmail.jtp?type=node&node=4653403&i=1 http://lists.boost.org/mailman/listinfo.cgi/boost-users
------------------------------ If you reply to this email, your message will be added to the discussion below:
http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... To unsubscribe from Mixing signals2 and asio mechanism failing, click herehttp://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=4653392&code=dXN0dWxhdGlvbkBnbWFpbC5jb218NDY1MzM5MnwtMTc0MzU1MDY5 . NAMLhttp://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml
-- ------------ spandan sharma -- View this message in context: http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... Sent from the Boost - Users mailing list archive at Nabble.com.

On Sunday, October 20, 2013, ustulation wrote:
I'd posted a query here too: http://stackoverflow.com/questions/19476578/mixing-boostasio-and-boostsi gnals2-giving-problems
In the hack there I have assumed that signals make a copy of slots before executing them and hence that hack would work -> it would delete the actual functor when connecting dummy() and then the copy once slot() returns (assuming that the signal had been fired and the control was inside slot() when stop() was called). Is that assumption correct (about copying the list of slots before executing them) ? I got it from: http://stackoverflow.com/a/4490785/1060004
It avoids copying the slot list unless it has to (it has to when you connect a slot while an invocation is in progress). If it does have to copy the slot list, it will clean up all the disconnected slots from the new copy and discard the old copy when all invocations using it complete. These are implementation details though, it would be best not to rely on them.

On Saturday, October 19, 2013 2:47 PM, ustulation wrote:
I've the following:
<1> a single instance of io_service object with a program life-time and several threads calling it's run() method. io_service::work is given to it so >that it never terminates (unless we stop it).
<2> class A which has boost::signals2::signal connecting functions for callback. * async operations (eg., async_read_until, async_write etc)
<3> class B which is derived from std::shared_from_this ; * has a composition of class A as std::unique_ptr which is instantiated in B's constructor ; <c> has functions/listeners which are registered with signals >of class A (eg., signals2::connection connectionObj = uniqPtrA->someSig.connect([=]{shared_from_this_ptrB->listenerFuncOfB();} uniqPtrA->);
<4> Another thread outside the thread-pool of <1> above which instantiates (and manages) class B: auto ptrB = std::make_shared(); //and further operations.
The problem is when I need to destroy ptrB I can't. For instance, i call some method of class B on ptrB to clear all connections it has with class A and allow ptrB to go out of scope, but class B destructor is never called:
{//local scope auto ptrB = std::make_shared(); ptrB->connectListenersToA(); /* eg auto self = shared_from_this(); connectionObj = uniqPtrA->someSig.connect([=]{self ->listenerFuncOfB();}); referring to <3> above */ //... do some operations ptrB->disconnectListenersWithA(); //eg connectionObj.disconnect(); referring to <3> above }//Scope ends I want ptrB to destroy the underlying pointer.
The ptrB destructor is never called because signals2::connection::disconnect does not seem to wipe out the given slot so the shared_ptr reference of B remains with the signal in class A as anonymous functor (due to lambda in <3> above) containing it does not get destroyed.
How do I achieve this?
Have you tried to use track_foreign so that boost uses the weak reference of your shared_ptr as an analogue for your connection object? You can even do this with std::shared_ptr, instead of boost::shared_ptr<>, since the traits specializations are in place (with a properly configured environment). Then your connect call looks like this: //ptrB->connectListenersToA(); // would do something like this uniqPtrA->someSig.connect(&B::listenerFuncOfB, this).track_foreign(shared_from_this()); If you do all of this, then you can just cut your shared_ptrs free and they'll get destroyed. Signals2 will store a weak_ptr instead, and get rid of that some time afterward. Best regards, M. Scott Mueller

oh i see. I did the same thing myself instead of using track_foreign. In my case the signal is a private member of a class so it's not directly accessible at the site which wants to register a callback. Instead the class with the signal has function exposed so i wonder if using track would be possible. I did something like this: boost::signals2::connection ClassWithSignal::registerListener(const std::function< void() > &refListener) { return m_signal.connect(refListener); } void SomeListenerClass::funct() { std::weak_ptr< SomeListenerClass > weakSelf = shared_from_this(); classWithSignal->registerListener( [weakSelf]{auto self = weakSelf.lock(); if(self) { self->myCallback(); }} ); } i did a few alpha test cases and seemed to pass thread safety issues. I guess this should work. I did not read into track() too much because i thought the registerListener(..) definition above does not permit it, but i don't know if that's true. BR// On Tue, Oct 22, 2013 at 12:07 AM, Scott Mueller [via Boost] < ml-node+s2283326n4653459h27@n4.nabble.com> wrote:
On Saturday, October 19, 2013 2:47 PM, ustulation wrote:
I've the following:
<1> a single instance of io_service object with a program life-time and several threads calling it's run() method. io_service::work is given to it so >that it never terminates (unless we stop it).
<2> class A which has boost::signals2::signal connecting functions for callback. * async operations (eg., async_read_until, async_write etc)
<3> class B which is derived from std::shared_from_this ; * has a composition of class A as std::unique_ptr which is instantiated in B's constructor ; <c> has functions/listeners which are registered with signals of class A (eg., signals2::connection connectionObj = uniqPtrA->someSig.connect([=]{shared_from_this_ptrB->listenerFuncOfB();} uniqPtrA->);
<4> Another thread outside the thread-pool of <1> above which instantiates (and manages) class B: auto ptrB = std::make_shared(); //and further operations.
The problem is when I need to destroy ptrB I can't. For instance, i call some method of class B on ptrB to clear all connections it has with class A and allow ptrB to go out of scope, but class B destructor is never called:
{//local scope auto ptrB = std::make_shared(); ptrB->connectListenersToA(); /* eg auto self = shared_from_this(); connectionObj = uniqPtrA->someSig.connect([=]{self ->listenerFuncOfB();}); referring to <3> above */ //... do some operations ptrB->disconnectListenersWithA(); //eg connectionObj.disconnect(); referring to <3> above }//Scope ends I want ptrB to destroy the underlying pointer.
The ptrB destructor is never called because signals2::connection::disconnect does not seem to wipe out the given slot so the shared_ptr reference of B remains with the signal in class A as anonymous functor (due to lambda in <3> above) containing it does not get destroyed.
How do I achieve this?
Have you tried to use track_foreign so that boost uses the weak reference of your shared_ptr as an analogue for your connection object? You can even do this with std::shared_ptr, instead of boost::shared_ptr<>, since the traits specializations are in place (with a properly configured environment). Then your connect call looks like this: //ptrB->connectListenersToA(); // would do something like this uniqPtrA->someSig.connect(&B::listenerFuncOfB, this).track_foreign(shared_from_this());
If you do all of this, then you can just cut your shared_ptrs free and they'll get destroyed. Signals2 will store a weak_ptr instead, and get rid of that some time afterward.
Best regards,
M. Scott Mueller _______________________________________________ Boost-users mailing list [hidden email] http://user/SendEmail.jtp?type=node&node=4653459&i=0 http://lists.boost.org/mailman/listinfo.cgi/boost-users
------------------------------ If you reply to this email, your message will be added to the discussion below:
http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... To unsubscribe from Mixing signals2 and asio mechanism failing, click herehttp://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=4653392&code=dXN0dWxhdGlvbkBnbWFpbC5jb218NDY1MzM5MnwtMTc0MzU1MDY5 . NAMLhttp://boost.2283326.n4.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml
-- ------------ spandan sharma -- View this message in context: http://boost.2283326.n4.nabble.com/Mixing-signals2-and-asio-mechanism-failin... Sent from the Boost - Users mailing list archive at Nabble.com.

On Tue, Oct 22, 2013 at 12:56 PM, ustulation
oh i see. I did the same thing myself instead of using track_foreign. In my case the signal is a private member of a class so it's not directly accessible at the site which wants to register a callback. Instead the class with the signal has function exposed so i wonder if using track would be possible. I did something like this:
boost::signals2::connection ClassWithSignal::registerListener(const std::function< void() > &refListener) { return m_signal.connect(refListener); }
You could pass the slot as a slot instead of a std::function: http://www.boost.org/doc/libs/1_54_0/libs/signals2/example/passing_slots.cpp or use templates to do perfect forwarding.
participants (3)
-
Frank Mori Hess
-
Scott Mueller
-
ustulation