From: Eric Niebler (eric_at_[hidden])
Date: 2004-05-05 11:11:45
Douglas Gregor wrote:
> On Monday 26 April 2004 09:53 am, David Abrahams wrote:
>>So, we're thinking of using the signals library in one of our
>>projects, but the lack of thread-safety is a concern for us. What
>>issues are preventing Boost.Signals from being made threadsafe?
> The biggest issue is granularity. Do we use signal-level locking or
> connection/slot-level locking? The former requires few locks, but constrains
> the coding style quite a bit, whereas the latter is going to incur a bit of
> overhead (a lock for every slot call, disconnect, etc.).
I was thinking there would be one lock object per signal object. I'm not
sure I understand the other option you mention. Could you explain a bit?
Regardless, locking behavior should be made a policy. That way, users
who are not interested in paying for thread-safety are accomodated.
> The other issue is
> correctness w.r.t. deletion of trackable objects, especially when dealing
> with the slot call iterators: for instance, consider a simple combiner that
> does this:
> while (first != last) *first++;
> If that "++" happens and first != last is true (because there are more slots
> to call), then another thread disconnects all of the signals from first up to
> last, then the dereference operator is Bad News.
I've been giving this issue some thought, and I think I can see a way to
make this thread-safe. Here's how:
1) signal::operator() grabs the lock
2) signal::operator() passes the slot iterators to combiner::operator()
3) slot_iterator::operator* does the following:
i) copies the slot into a local
ii) releases the lock
iii) calls the slot through the local
iv) reaquires the lock.
4) slot_iterator::operator++ skips any nulled-out slots (note that it
always executes when the lock is held)
5) combiner::operator() returns and signal::operator() releases the
Now, you must be careful in signal::connect() and signal::disconnect()
to do nothing that would invalidate the slot iterators. Suppose they
were std::list::iterators, and that signal::disconnect() merely nulled
out slots instead of removing them from the list. Then this would work.
But it needs to be documented that slot_iterators are only valid for
the duration of combiner::operator(). (That is, you can't copy them into
a global and use them after the lock has been released.)
What do you think?
-- Eric Niebler Boost Consulting www.boost-consulting.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk