Signals

Signal / slot architecture is a replacement for the usual 'check for something' approach to inter-module communication. The philosophy is as such, that an object informs ( sends a 'signal' ) to all interested parties about some events and does not care about what happens. The class of this object provides an interface ( a slot ) to which interested parties register a handler, which actually is a function that the originator has to call.

 

class boom_boom
{
    void boom_boom_slot( function * _handler )
    {
        boom_boom_signal.register_handler( _handler );
    }

    void explode()
    {
        if( boom_boom_event_occured )
            boom_boom_signal.signal_registered();
    }
private:
    signal boom_boom_signal;
};

class bang_bang
{
    on_boom_boom()
    {
        print “zomg!”;
    }
};
// ... code
boom_boom originator;
bang_bang receiver;
    
originator.boom_boom_slot( &reciever.on_boom_boom )
originator.do_stuff();

// now, whenever boom_boom_event occurs
// bang_bang::on_boom_boom shall be called


In TE slots/signals are used widely to communicate between the GUI and actual business logic and sometimes between modules.

When using the slot/signal architecture care must be taken to avoid sending signals from a signal handlers. Per se this is not a problem, but may lead to long chains of handling of signals and in pathological cases to loops. This usually degrades the quality of service and may be difficult to debug.

TE constructs its slot/signal architecture with the use of three boost libraries:

boost::bind - used to create a handler objects

boost::function - to pass the signal handler to the signal originator

boost::signals - to actually send signals

To manage connections between modules a separate entity is introduced in the 'common' module called 'automatic_connection_handle'. This is a class which wraps around 'boost::signals::connection' and automatically handles the connection to the originator.


#include "boost/function.hpp"
#include "boost/signals.hpp"
#include "boost/bind.hpp"
#include "common/automatic_connection_holder.hpp"

class originator
{
public:
    common::automatic_connection_holder
    add_some_event_handler( boost::function< void( int ) > const & _handler )
    {
        return
            common::automatic_connection_holder::create(
                m_signal.connect( _handler )
            );
    }
private:
    boost::signal m_signal;
};

class receiver
{
public:
    receiver( originator & _originator )
    {
        m_on_some_event_handle
            =    _originator.add_some_event_handler(
                    boost::bind(
                        &reciever::on_some_event
                    ,    this
                    ,    _1
                    )
                );
    }

    void on_some_event( int _parameter )
    {
    }
private:
    common::automatic_connection_handle m_on_some_event_handle;
};

 

The connection between receiver and originator will exist as long as automatic_connection_handle exist.