User Documentation
RAVL, Recognition And Vision Library
DEVELOP HOME PAGE CLASS LIST CONTENTS
Ravl - OS - Signals


Thread safe signals

What are signals ?

A Signal is essentially a list of functions to call on an event. Signals currently may have 0,1,2 or 3 parameters which will be passed to the functions in the list. The advantage of using signals over simple function pointers is the exact form of the or number of functions need not be known by the provider of the signal. They are simpler to use that virtual functions as no new class need be defined.

A useful feature of the signal implementation is that two signal structures can be connected together without creating a reference counted dependence between them. If either of the signal structures is destroyed the connection between them is automaticly broken.

If you are in a situation where you only want to call 1 function, but still want flexibilty in the exact form of that function its worth looking at the Calls and Triggers in the RAVL core.

Notes on RAVL's signal implementation

The RAVL signal system has been inspired by libsigc++, but written to work with RAVL style reference counting.

Features:

  • Signal objects are reference counted.
  • Adding and removing connections is thread safe.
  • The default implementation makes copies of the objects the signal will be delived to, enabling it to call methods of reference counted objects safely.

How to use them.

The following code fragments are from the example code for Signal1C. The complete example is here.

The signal code is part of the threads library so you have to add RavlThreads to your USESLIBS line in defs.mk. We're going to use signals with 1 paramiter so we include the Signal1 header file.

#include "Ravl/Threads/Signal1.hh"
    

Creating a signal is simple, just declare it as a variable with an appropriate default value. The following code creates an integer signal with a default value of 0.

Signal1C sig(0);
    

Calling global functions.

Suppose we have a function 'PrintNumberA' we wish to be called when the signal is triggered. Note, the arguments of methods must always be non-const references to a type, and the functions should always return a bool. This significanly simplifies the implementation as it avoids implementing code for all possible combinations argument types and return types.
bool PrintNumberA(int &i) {
  cout << "PrintNumberA called with value " << i << "\n";
  return true;
}
This an be connected to the signal with the Connect(..) command.
Connect(sig, &PrintNumberA);
Similarly if you wish to connect a second signal to this you again call Connect(...).
Signal1C sig2(1);

Connect(sig, sig2);
Finally to send a signal you use the () operator on the signal itself. If you omit a paramiter the default value you initalise it with will be used instead. Calling the following:
sig2(3); // Send the signal with a value of 3.
Prints the message
PrintNumberA called with value 3
The arguments of the function do not have to match the signal you are calling. If the function takes more paramiters than you are using you can supply the values when you call connect. To connect the following function 'PrintNumber2':
bool PrintNumber2(int &i,RealT &v2) {
  cout << "PrintNumberA called with value " << i << " v2=" << v2 << "\n";
  return true;
}
you supply the extra paramiter at the end of the connect command, like this:
Connect(sig, &PrintNumber2,0,0.1);
Note: you have to supply values for all arguments of the function even where they are provided by the signal. When the signal is triggered it will call 'PrintNumber2' with the the first paramiter from the signal and the second set to a real value of 0.1.

Calling class methods.

Calling class methods is a little more complicated. You have to tell the system which instance of the class to call the method on. Suppose you had the following class:
class MyClassC {
public:
   bool Print(int &i) {
     cout << "Value=" << i << "\n";
   }
};
There are two ways to connect to a method you can either connect to a copy of the object (essentail for reference counted objects.) or to a reference to it. If you use a refrence it is the programmers responsibility to ensure the object is valid when a signal is called.

To connect with a copy you would call Connect as follows:

MyClassC xyz;

Connect(sig,xyz,&MyClassC::Print);

To connect with a reference you would use:

MyClassC xyz;

ConnectRef(sig,xyz,&MyClassC::Print);
Note: There are some potential race conditions in multi-threaded applications if you use the reference method of connecting to classes. It is possible that the class processing a signal is destroyied before the call is complete with unpredictable results. This is guaranteed not to happen with the reference counted calls, the signal mechanism ensures a reference is kept to the object until all calls are complete.

Normal classes:

 Signal0C Signal 0 handle.
 Signal2C Signal with 2 arguments
 Signal3C Signal with 3 arguments.
 Signal1C Signal with 1 argument
 SignalConnectionSetC Signal connection set body.

Normal functions:

 Connect(Signal0C &,Signal0C &) Connect signal to another signal.
 Connect(Signal0C &,Signal0FuncBodyC::FuncT) Connect signal to a function with 0 args.
 Connect(Signal0C &,const DataT &,bool (*func)() ) Connect signal to a method with 0 args.
 ConnectRef(Signal0C &,DataT &,bool (*func)() ) Connect signal to a method with 0 args.
 operator <<(ostream &,const Signal2C &) IO Operator.
 Connect(Signal0C &,Signal2C &) Connect a signal to another signal.
 operator <<(ostream &,const Signal3C &) IO Operator.
 Connect(Signal0C &,Signal3C &) Connect to a signal
 Connect(Signal0C &,const ObjT &,bool (*func)(Data1T &,Data2T &,Data3T &) ,const Data1T &,const Data2T &,const Data3T &) Connect a signal to a method.
 ConnectRef(Signal0C &,ObjT &,bool (*func)(Data1T &,Data2T &,Data3T &) ,const Data1T &,const Data2T &,const Data3T &) Connect a signal to a method.
 operator <<(ostream &,const Signal1C &) IO Operator.
 Connect(Signal0C &,Signal1C &) Connect two signals together.
 Connect(Signal0C &,bool (*func)(DataT &) ,const DataT &) Connect a signal to a function.
 Connect(Signal0C &,const ObjT &,bool (*func)(DataT & arg) ,const DataT &) Connect a signal to a method.
 ConnectRef(Signal0C &,ObjT &,bool (*func)(DataT & arg) ,const DataT &) Connect a signal to a method.

Advanced classes:

 SignalConnectorC Signal connector handle.
 SignalInterConnect0C class for signal interconnector with 0 args.
 Signal0FuncC Signal a function
 Signal0MethodC Signal a method.
 Signal0MethodRefC Signal a method.
 SignalInterConnect2C class for signal interconnector with 1 arg.
 Signal2FuncC Signal a function
 Signal2MethodC Signal a method.
 Signal2MethodRefC Signal a method.
 SignalInterConnect3C class for signal interconnector with 1 arg.
 Signal3FuncC Signal a function
 Signal3MethodC Signal a method.
 Signal3MethodRefC Signal a method.
 SignalInterConnect1C class for signal interconnector with 1 arg.
 Signal1FuncC Signal a function
 Signal1MethodC Signal a method.
 Signal1MethodRefC Signal a method.
Documentation by CxxDoc: Tue Aug 13 10:00:52 2002