
Timmo Stange wrote:
However, I'd like to focus on the problem at hand. I don't know how closely you have looked at Frank's thread_safe_signals, so I describe the part of the implementation I had in mind when I raised my "performance warning":
Frank uses a vector of shared_ptrs to tracked objects as a member of his slot_call_iterator. That made me worry a little bit already, because I usually don't expect a temporary copy (through pass by value or other means) of an iterator to involve a vector copy and reference count adjustments for an arbitrary number of pointers.
The slot_call_iterator idiom is another thing that I don't like in the original Signals design; it feels too clever for its own good, and is there to support a nice way of using combiners. I've nothing against combiners per se, but the majority of the signal uses do not involve slot returns or combinations thereof. If I had to redesign the library, I'd explore a simple void operator() that just calls the slots, and a separate template<class Cm> void call_and_combine( Cm & cm, ... ); that calls cm( s( ... ) ) for each slot s. My initial iteration of this hypothetical design would also incur several shared_ptr/intrusive_ptr copies on operator() to address the thread safety issues in the most obvious "snapshot" way, that is, the signal invokes the slots that were connected at the time operator() was called. Subsequent concurrent modifications to the slot container do not affect the invocation in progress. This has the advantage of being highly scalable and deadlock-resistant. Such an approach may turn out to not be acceptable, though, given that the majority of signal benchmarks place heavy emphasis on operator() calls.