From Signals back to Callbacks

Most signals in our project are never planned to be a signal, e.g. whole communication between looslely coupled parts of a component. They could be exchanged through non-thread-safe callbacks (with boost::bind / boost::function) instead of boost::signals2' signals, as we know their instantiation time (during component init) and they usually just link to one object. Interestingly not only performances increases, also compile time seems to be heavy bound by boost::signals2. The compiler was g++ 4.4 (current Ubuntu)
Testprogram:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/signals2.hpp>
void test1 (){
std::cout << "Hello World" << std::endl;
}
struct A {
typedef boost::function<void ()> callback_type;
typedef boost::signals2::signal< void ()> signal_type;
void doIt (){
cb ();
}
void doItSig (){
sig ();
}
callback_type cb;
signal_type sig;
};
int main (int argc, char * argv []){
A a;
a.cb = test1;
a.sig.connect (test1);
a.doIt ();
a.doItSig ();
return 0;
}
Backtrace with Callback via boost::function
#0 test1 () at main.cpp:7 #1 0x00000000004071fc in boost::detail::function::void_function_invoker0::invoke (function_ptr=...) at /usr/local/boost/include/boost/function/function_template.hpp:112 #2 0x0000000000403023 in boost::function0::operator() (this=0x7fffffffe170) at /usr/local/boost/include/boost/function/function_template.hpp:1013 #3 0x0000000000402924 in A::doIt (this=0x7fffffffe170) at main.cpp:15 #4 0x0000000000401b1a in main (argc=1, argv=0x7fffffffe2b8) at main.cpp:32
Backtrace with Callback via signals2:
#0 test1 () at main.cpp:7 #1 0x00000000004071fc in boost::detail::function::void_function_invoker0::invoke (function_ptr=...) at /usr/local/boost/include/boost/function/function_template.hpp:112 #2 0x0000000000403023 in boost::function0::operator() (this=0x6181b8) at /usr/local/boost/include/boost/function/function_template.hpp:1013 #3 0x000000000040acbd in boost::signals2::detail::signal0_impl, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker::m_invoke(boost::shared_ptr >, boost::signals2::slot0 >, boost::signals2::mutex> > const&, boost::signals2::detail::void_type const*) const (this=0x7fffffffe0a0, connectionBody=...) at /usr/local/boost/include/boost/signals2/detail/signal_template.hpp:351 #4 0x000000000040a037 in boost::signals2::detail::signal0_impl, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker::operator()(boost::shared_ptr >, boost::signals2::slot0 >, boost::signals2::mutex> > const&) const (this=0x7fffffffe0a0, connectionBody=...) at /usr/local/boost/include/boost/signals2/detail/signal_template.hpp:340 #5 0x0000000000408c69 in boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >::dereference() const ( this=0x7fffffffdea0) at /usr/local/boost/include/boost/signals2/detail/slot_call_iterator.hpp:82 #6 0x0000000000407d3a in boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >::reference boost::iterator_core_access::dereference, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> > >(boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> > const&) (f=...) at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:516 #7 0x0000000000406bd0 in boost::iterator_facade, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >, boost::signals2::detail::void_type, boost::single_pass_traversal_tag, boost::signals2::detail::void_type const&, long>::operator*() const (this=0x7fffffffdea0) at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:634 #8 0x0000000000405bf0 in void boost::signals2::optional_last_value::operator(), int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> > >(boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >) const (this=0x618100, first=..., last=...) at /usr/local/boost/include/boost/signals2/optional_last_value.hpp:55 #9 0x0000000000404a69 in void boost::signals2::detail::combiner_invoker::operator(), boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> > >(boost::signals2::optional_last_value&, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex>::slot_invoker, std::_List_iterator >, boost::signals2::slot0 >, boost::signals2::mutex> > >, boost::signals2::detail::connection_body >, boost::signals2::slot0 >, boost::signals2::mutex> >) const ( this=0x7fffffffdfde, combiner=..., first=..., last=...) at /usr/local/boost/include/boost/signals2/detail/result_type_wrapper.hpp:64 #10 0x0000000000403bba in boost::signals2::detail::signal0_impl, int, std::less, boost::function, boost::function, boost::signals2::mutex>::operator()() (this=0x618010) at /usr/local/boost/include/boost/signals2/detail/signal_template.hpp:246 #11 0x0000000000403050 in boost::signals2::signal0, int, std::less, boost::function, boost::function, boost::signals2::mutex>::operator()() (this=0x7fffffffe190) at /usr/local/boost/include/boost/signals2/detail/signal_template.hpp:675 #12 0x0000000000402942 in A::doItSig (this=0x7fffffffe170) at main.cpp:19 #13 0x0000000000401b26 in main (argc=1, argv=0x7fffffffe2b8) at main.cpp:33
Compile Time with signals2:
$ time g++ -I/usr/local/boost/include/ -g main.cpp -o main
real 0m1.653s
user 0m1.500s
sys 0m0.150s
Compile Time with just callbacks (signals commented out):
time g++ -I/usr/local/boost/include/ -g main.cpp -o main
real 0m0.581s
user 0m0.530s
sys 0m0.070s
Disadvantages:
- You have to bound them - in contrast to signals, this is Ok for components, the parts could use a default-handler
- They are not so easy to couple as signals (you don't have a connect keyword and no disconnect which would go back to the default handler)
- Callbacks are no signals, so you have loose all signal-features
But you can "upgrade" them to signals: Just put in a signal as target(No, that won't work because of a noncopyable constructor) But you can add a multiplexer which forwards callbacks to a real signal. Not beautiful, but working.
Update
With boost::signals (the first non-threadsafe version) the compile reduces to 0.9s; but the backtrace looks still long and the exe size is big.
#0 test1 () at main.cpp:12
#1 0x0000000000404e9f in boost::detail::function::void_function_invoker0<void (*)(), void>::invoke (function_ptr=...)
at /usr/local/boost/include/boost/function/function_template.hpp:112
#2 0x0000000000402d4b in boost::function0<void>::operator() (this=0x6152f8) at /usr/local/boost/include/boost/function/function_template.hpp:1013
#3 0x0000000000405705 in boost::signals::detail::unusable boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >::operator()<boost::signals::detail::connection_slot_pair>(boost::signals::detail::connection_slot_pair const&) const (this=0x7fffffffe010, slot=...)
at /usr/local/boost/include/boost/signals/signal_template.hpp:119
#4 0x0000000000405494 in boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>::dereference() const (this=0x7fffffffdfd0) at /usr/local/boost/include/boost/signals/detail/slot_call_iterator.hpp:61
#5 0x000000000040510a in boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>::reference boost::iterator_core_access::dereference<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator> >(boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator> const&) (f=...)
at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:516
#6 0x0000000000404ce8 in boost::iterator_facade<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>, boost::signals::detail::unusable, boost::single_pass_traversal_tag, boost::signals::detail::unusable const&, long>::operator*() const (this=0x7fffffffdfd0) at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:634
#7 0x000000000040482a in postfix_increment_proxy (this=0x7fffffffdf0f, x=...) at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:144
#8 0x00000000004041c6 in boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>, boost::signals::detail::unusable, boost::signals::detail::unusable const&, boost::single_pass_traversal_tag>::type boost::operator++<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>, boost::signals::detail::unusable, boost::single_pass_traversal_tag, boost::signals::detail::unusable const&, long>(boost::iterator_facade<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>, boost::signals::detail::unusable, boost::single_pass_traversal_tag, boost::signals::detail::unusable const&, long>&, int) (i=...)
at /usr/local/boost/include/boost/iterator/iterator_facade.hpp:732
#9 0x00000000004037df in void boost::last_value<void>::operator()<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator> >(boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>, boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<void>::caller<boost::function<void ()()> >, boost::signals::detail::named_slot_map_iterator>) const (this=0x615148, first=..., last=...)
at /usr/local/boost/include/boost/last_value.hpp:49
#10 0x0000000000402eaa in boost::signal0<void, boost::last_value<void>, int, std::less<int>, boost::function<void ()()> >::operator()() (this=0x7fffffffe140)
at /usr/local/boost/include/boost/signals/signal_template.hpp:354
#11 0x000000000040267a in A::doItSig (this=0x7fffffffe120) at main.cpp:21
#12 0x00000000004019e9 in main (argc=1, argv=0x7fffffffe2b8) at main.cpp:35
Img: CC-BY-ND, by 92wardsenatorfe