Boost logo

Boost :

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
    lock.

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