wiki:soc/2007/SignalNetwork

Version 2 (modified by Stjepan Rajko, 15 years ago) ( diff )

--

Introduction

The Signal Network library aims to facilitate the implementation and interconnection of objects into signal networks using Boost.Signals. To understand the concept of signals (data generators / senders) and slots (data consumers / receivers), please see the Boost.Signals documentation and the associated tutorial.

This is a proposal for development of the Signal Network library as a part of Google Summer of Code and evential inclusion into Boost. Depending on what is preferred, the Signal Network library can be included into Boost.Signals or considered as a separate library.

If you're interested, you may want to examine the documentation for the prototype implementation.

The Signal Network library is to provide

  • a concise operator based syntax that facilitates construction and readiblity of signal networks
  • mechanisms that facilitate construction of signal network components
  • implemented building-block components that are applicable to a wide range of signal networks
  • detailed documentation (tutorial, examples and reference) of all of the above

The development platforms are

  • OS X / Xcode with Apple's branch of GCC
  • Windows / MSVC8.0

Motivation

Boost.Signals provides an excellent mechanism which can be used to dynamically configure the flow of data within a program. This is helpful for registering callbacks, for event passing, and for signal processing applications.

However, when dealing with more complicated networks, there are several improvements to Boost.Signals that could facilitate the construction, configuration, and execution of said networks. Several categories which could use some improvement are listed below.

For simplicity, the examples in this documentation deal with signals which carry numbers, and components which manipulate them. The same principles are applicable to many kinds of signal oriented applications (e.g., ones where the signals carry event information, video frames, audio buffers, etc.).

Conciseness and readability of code

In complex signal-based applications, many components are signal filters or some kind (i.e., they receive some input, process it, and send some output). For processing of any substantial complexity, each type of filter is most likely implemented as a class, with one or more member boost::signal objects serving as signal outputs, and one or more member functions serving as input slots.

Suppose we would like to connect a network consisting of a signal generator, a couple of filters, and a couple of signal consumers (say, display components). The components might be declared as follows:

signal_generator generator; // contains a boost::signal accessible via signal_generator::default_signal()
signal_filter1 filter1; // contains a boost::signal accessible via signal_filter1::default_signal(),
                                                // and a slot function operator()
signal_filter2 filter2; // contains a boost::signal accessible via signal_filter2::default_signal(),
                                                // and a slot function operator()
signal_display display1, display2; // contains a slot function operator()

To connect the network, the following would be necessary using Boost.Signals:

Boost.Signals syntax:

// connect the generator to filter1
generator.default_signal().connect(boost::bind(&signal_filter1::operator(), boost::ref(filter1)));
// connect filter1 to filter2
filter1.default_signal().connect(boost::bind(&signal_filter2::operator(), boost::ref(filter2)));
// connect the output of each filter to a display
filter1.default_signal().connect(boost::bind(&signal_display::operator(), boost::ref(display1)));
filter2.default_signal().connect(boost::bind(&signal_display::operator(), boost::ref(display2)));	

The code above is rather long to write, and might not be particularly readable. What we would like to do instead is something more concise and readable:

Proposed/desired syntax:

// connect (>>=) generator to filter1,
// branch (|) from filter1 to both display1 and filter2,
// and connect (>>=) filter2 to display2.
generator
	>>= filter1
		| display1
		| filter2 >>= display2;

The above code is much more concise, and after getting familiar with the syntax, understanding the structure of the signal network is easy and quick.

Flow control components

In many cases, we would like to modify the flow of signals after the network has been constructed. Boost.Signals allows us to change the network by disconnecting old or creating new connections. So, for example, if we wanted to introduce a second signal generator into the system (e.g., generator2), we could use signal::disconnect (or signal::disconnect_all_slots) and signal::connect to toggle between the two sources:

Boost.Signals flow control:

// switch to the other signal generator:
generator.default_signal().disconnect_all_slots();
generator2.default_signal().connect(boost::bind(&signal_filter1::operator(), boost::ref(filter1)));

There are a few potential problems with this approach. First, the syntax is again perhaps a little too involved. And second, altering the network while signals are being sent may require extra care (especially in multi-threaded settings). Hence, depending on the situation, it might be difficult to use this approach to alternate between the two sources (perhaps a custom object would need to be written to choose the appropriate source).

Instead, it would be desirable to have ready-made components which can be used to alter the flow of signals without changing the architecture of the network:

Proposed/desired flow control:

// introduce a selector into the network
signal_selector selector;

// the generators are now connected to the selector
generator >>= selector.slot1;
generator2 >>= selector.slot2;

// and the rest of the network is now constructed as follows:
selector
	>>= filter1
		| display1
		| filter2 >>= display2;
		

// Now we could choose the source as follows:
selector.select(1); // select input coming into slot1
...
selector.select(2); // select input coming into slot2
...
selector.select(0); // select no input

The latter approach offers more robust control, and can be implemented in a thread-safe way (safe even when the generated signals are in threads separate from the reconfiguring thread). Similar arguments can be made for other flow control components such as junctions and gates.

Other building-block signal network components

There are many other components that are usable in various signal network settings. The Signal Network library would provide a set of such commonly needed components, such as templates for signal generators, collectors, threading components, etc.

Note: See TracWiki for help on using the wiki.