cgvis the IT thing

From Signals back to Callbacks

Posted on February 4, 2010

Traffic Light! by Flickr user 92wardsenatorfe, CC-BY-ND
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&gt;::slot_invoker::m_invoke(boost::shared_ptr &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; const&amp;, 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&gt;::slot_invoker::operator()(boost::shared_ptr &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; const&amp;) 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&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;::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&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;::reference boost::iterator_core_access::dereference, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;(boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; const&amp;) (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&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;, boost::signals2::detail::void_type, boost::single_pass_traversal_tag, boost::signals2::detail::void_type const&amp;, long&gt;::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&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;(boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;) 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&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;(boost::signals2::optional_last_value&amp;, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;, boost::signals2::detail::slot_call_iterator_t, int, std::less, boost::function, boost::function, boost::signals2::mutex&gt;::slot_invoker, std::_List_iterator &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt; &gt;, boost::signals2::detail::connection_body &gt;, boost::signals2::slot0 &gt;, boost::signals2::mutex&gt; &gt;) 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&gt;::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&gt;::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

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


Trackbacks are disabled.