Some time ago Terry Wilmarth posted the blog about Aggregators in TBB. In this blog I want to explore the design space of the pattern. The post contains lots of code, and I will use mostly the term Combiner below.



So what is a combiner? It is a mutual exclusion primitive similar to a mutex. But when using a combiner you explicitly pass the critical section function, and it allows more flexibility with respect to its execution. Namely a thread can execute the critical section on behalf of another thread. Here is a simple usage example:

combiner_t* c = combiner_create(&my_critical_section); ... combiner_execute(c, &arg); // at this point my_critical_section(&arg) function has been executed, // but not necessary by the current thread.

This is analogous to:

mutex_t *m = mutex_create(); … mutex_lock(m); my_critical_section(&arg); mutex_unlock(m);

The reasonable question -- how is it better than mutex? If we combine/aggregate several critical sections from different threads (here is where the name came from) into a single critical section and give it to a single thread to execute, it can have significant impact on cache performance. Note if there is no combing opportunities, the primitive behaves exactly as a mutex -- lock, execute the critical section in the current thread, check that there is no combining opportunities, unlock, return.