From: Karl Nelson (kenelson_at_[hidden])
Date: 2000-11-18 12:17:41
> > I would be the one and only author of libsigc++. :-)
> > Currently, I am trying to shave off the last few bytes
> > in the interstructure and trying to make the functors
> > sharable in some kind of threadsafe manner.
> Then we really need to collaborate, at least with ideas ;). I want
> callbacks for the Boost thread implementation, so obviously it must
> be thread safe.
Well, this is certianly the point of the libsigc++ rewrite to
pick up the few features it was missing such as functor comparision,
functor copying, and improved threadsafety.
> The Boost libraries today are distributed as source only, so an m4
> macro is a big consideration (though the distribution can contain pre-
> generated source as you pointed out). I don't think anyone is
> considering distributing binary packages.
I distribute the m4 just becasue there is no way to
build the whole set of available templates on the fly.
Libsigc++ builds 0 through 7 argument versions, but in the rare
case they need more it is necessary to use m4 to build it.
Using a lambda code I could weed out some the structure to where you
Slot<void, Args2<int,int> >
Thus separating out the structure of the signals and slots from
the call structure. However, this greatly convolutes the calling
structures and makes for a cluttered and ugly interface.
> > > not sure that's a good base for us to start from here.
> > Well, I am the only author and have in the past discussed things
> > with boost. It is currently a LGPL library, but I hold option
> > and have signed X-style BSD copies of classes at request.
> > My other libraries are being donated to Free Software Foundation,
> > for which I am a strong supporter. I only consider boost
> > when there is a strong community need for a common standard.
> > I currently am short of time and when time becomes available
> > will be submitting the previously discussed formating stream to
> > boost.
> > Hopefully, once sigc++ is simplified and made threadsafe I will
> > submit it. Currently, I consider the code base too young
> > to be ready for standardization.
> Ok, then I'll start to address the issues I see in libsigc++ over
> what we've been discussing.
> First, libsigc++ is really a Signal/Slot implementation which isn't
> quite the same thing as a callback. Signals/Slots are really a multi-
> casting concept based on callbacks. The thread library isn't really
> appropriate for Signals/Slots while it's very appropriate for
> callbacks. I'd prefer to see the simpler Concept of Callback fleshed
> out and implemented after which the Signal/Slot can be built on top
> (or, if efficiency suggests so the implementation may be built
> totally on it's own... it's just a seperate and distinct Concept to
Okay 3 issues here...
1) Should a library have a callback and later build slots?
I have had that arguement a number of times and what always gets pointed
out is that building just callbacks causes some many problems
it isn't worth it. Libsigc++ provided the class Callback# which
was exactly that. It was a union of pointers, function pointers,
methods with objects etc. However, as I discovered you
would have to build your own set of factories for those callbacks
in effect doubling the size of the library. Second, you can't
really build adaptors with the callbacks because they would
require chaining of resources. In other words, slots
in the clean up capablity allow cleaning up the objects which
allow adaptors. So Callbacks are of limited use. Further,
they aren't all that useful to build the Slots themselves as
the slot just ends up carrying arround the bulk of
a general callback where it could be trimmed down.
2) Can a Slot be a Callback?
The answer to this is yes. That is that if I make a Slot like
concept with the ablity to disconnect and clean up the
traces between objects, I don't have to use that path.
Thus it is a very common misunderstanding the to use SigC
you must use SigC::Object. You don't, you simply must use a different
factory to produce pure callbacks rather than slots. Thus
nothing in SigC requires SigC::Object other than SigC internals.
3) Can a Signal/Slot be used in Threads?
There are issues but they aren't as bad as they first appear.
Ther real problem is that only one thread can be destroying or
adding things to a list at one time. Some of this
can be done properly with make before break and atomic flags on
the lists. Further, the reference counters have to be protected.
Really advanced adaptors and signals are out unless the signal
queue is protected internally. But for the most part it
So what is a Slot exactly
- Acts as a callback
- Can clean up if the target is removed
- Can clean up if the source is removed
- String-like construction (pointer to a functor which can be shared
copied and manipulated)
A bound pointer (Borlands pure callback idea) lacks the 3rd property
and thus can't be used as adaptors. Many callback systems lack 2nd.
Okay so you quickly think why can't I just add a list in the
the object the callback is pointed to to kill the callback and
make a slot? But that creates its own problem, who cleans up
the list if the callback goes away? Basically you end up with
dependency loops, which require a unified method to handle the
internal cleanups. Adaptors to callbacks also cause this
dependency loop because the data in the adaptor can become stale.
Thus for efficency building a really good Signal/Slot library
which has the ablitity to do the event and threading is
the right approach.
> Second, if I'm not mistaken libsigc++ relies on a base class of
> _Sig::Object, though it does use adapters and generators to hide this
> in some circumstances. This is probably needed by libsigc++ to
> handle such things as unregistering, but it seems heavy handed for
> callbacks. (Note, this is probably an unfair criticism because we do
> something very similar with the bridge pattern and external
> polymorphism and it wouldn't take much to extend the concrete
> implementation classes to include signal functionality. This might
> even be an argument in favor of Doug Gregor's event() method.)
And it is an incorrect critism. There is no such requirement unless
unregistering is desired. You can form slots to arbitrary
methods or to C functions and still use the adaptor structures
without ever including SigC::Object in your file. The
only difference between making a registered or floating slot
is which factory you use.
> Third, use of a slot() generator appears to just be reduplication of
> effort better handled by Lambda and other functor libraries. (Note,
> this too may be an unfair criticism. Doug's event() method is no
> different. It may be advantageous to have two such generators, one
> to generate simple callbacks and the other to generate the callbacks
> with additional functionality required for Signal/Slot useage. This
> idea would require serious thought, however, to insure type safety
> and compatibility.)
Well, signal/slots are always going to require their own generators
as to get the unregistering capablity you must form both the
bound pointer and make the dtor mechanism to clean up.
> These are preliminary thoughts. I'll have to take a much closer look
> at libsigc++ now. I'd be very interested in hearing your thoughts on
> this. If we can come to some consensus here I may be of help to you
> in adding thread safety to libsigc++ and in submitting the library to
I won't look at libsigc++ TOO closely, because there was a lot
of crap there which I quite frankly and throwing out.
Things that are going... Handles, Scopes, Callback#. These
were attempts to make a unified type ie a Slot was a Object
etc. These bad attempts are going away. The reduced library is
a fraction of the size. Further I am paring out the
use of some memory elements. Thus the cost of an object slot
is going from 64 bytes to 28 and so on.
With luck the cost of a good slot system will be almost the
same as the cost of a good callback system.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk