29.4TheDispatcher 455
If no element is available at all after checking each thread’s FIFO, the func-
tion returns false. The function does not wait for an element, and lets the caller
decide what to do if none are available. It can decide to sleep, to do some other
work, or to retry if low latency is important. For example, in a sound system, the
update might process all commands until there are no commands left and then
update the system.
To prevent any other thread from reading from the aggregator, we also regis-
ter the reader thread and store its identifier. The identifiers are then matched in
Pop() in debug mode.
This implementation does not allow more than a fixed number of threads.
But generally in a game application, the number of threads is fixed, and a thread
pool is used, thus limiting the need for a variable-size architecture.
From a performance point of view, care should be taken with memory usage.
Depending on the architecture, different FIFO structures should be placed on dif-
ferent cache lines. To ensure consistency, when a thread writes to a memory slot,
the corresponding line cache is invalidated in all other processor caches. An up-
dated version must be requested by the thread reading the same cache line. The
traffic on the bus can increase substantially, and the waiting threads are stalled by
cache misses. The presented implementation does not take this problem into ac-
count, but an ideal solution would be to align the FIFO items with cache lines,
thus padding the item up to the cache line size so that neighbor items are not
stored in the same cache line.
29.4TheDispatcher
In the case of a single producer and multiple consumers, we can create a dis-
patcher. The dispatcher is a single writer, multiple readers queue. This system
can be used to dispatch work to several threads, and it can be implemented using
the SWSR FIFO. The implementation is similar to that of the aggregator.
29.5TheGateway
The final structure presented here is the gateway. It is a multiple writers, multi-
ple readers queue. This queue is not really a FIFO anymore since a thread must
be used to pop items from the aggregator and push them in the dispatcher. Its role
is quite similar to a scheduler, with the central task of distributing items. This
distribution can process the data before dispatching it. Nothing prevents this cen-
tral thread from reading every possible item, doing some work on them (e.g.,
sorting or filtering), and finally pushing them to the reader threads. As an exam-