
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