ProducerConsumer overview

ProducerConsumer classes

The following class diagram shows the essential structure of the ProducerConsumer component class. Note that to aid clarity operations are omitted from all classes and attributes are only shown for ProducerConsumer:


This class diagram shows:
  • Connection points - There are two: Consumer and Producer
  • Connections - There may be many consumer connections and many producer connections
  • Elements - There may be many ProducerConsumerElements within a ProducerConsumer
  • Connection Mapping - A default connection mapping is provided
  • Locking - Each element has its own element lock to prevent re-entry

Introduction to producer-consumer concepts

Flow control

The primary function of the ProducerConsumer component is to provide flow control. This makes it possible to precisely control the number of iterations that producers can run ahead of consumers throughout an application, allowing enough depth to give the required concurrency while ensuring consumers can always keep up.

The flow control processing is deferred to the ProducerConsumerElement class, which handles flow-control for a particular element of the ProducerConsumer. For more detail on flow control please refer to the ProducerConsumerElement overview.

Element arrays

When using ProducerConsumer, all sub-tasks must always be single instances (i.e. not arrays). This is because the dimensionality is specified by the task's Dimensions property, which is used by the ProducerConsumer to instantiate the correct number of parallel instances of the component state as shown in the following component diagram:


Note: Arrays are implemented this way to ease the mapping between elements across connections - by deferring all array dimensions down to the ProducerConsumer, there is only one array index to worry about, which lives in ProducerConsumer. Without this, the mappings would need to know about the higher levels in the task hierarchy, which would break the layered architecture.

Element indices

The ProducerConsumer contains a flat array of ProducerConsumerElements and the elements are indexed using a single flat index (i.e. the multi-dimensionality is not preserved at this level). There are several reasons why this approach is used:
  • Connection mappings are simpler to describe
  • Absolute dimensions are dependent on where a component is instantiated so can't be fixed anyway
  • Simple helper methods to translate between flat and multi-dimensioned arrays are provided

Connection mappings

The following component diagram shows a single connection between two ProducerConsumers and the mapping of links within that connection:


In this example the ProducerConsumers at either end of the connection both have three elements (i.e. the product of their parents' dimensions is equal to three). There are several ways that the elements on the left could be mapped to the elements on the right:
  • N-to-N - Left element N maps to right element N
  • N-to-all - Left element N maps to all right elements
  • Ad-hoc - Left elements are mapped in an irregular way to right elements

If the dimensions of each are different (as shown in the following example) then the first of these options is not available:


A standard mapping is provided by the SimpleConnectionMapping class that selects the simple connection options depicted in the previous examples such that:
  • If dimensions are equal, then each element is mapped to its corresponding opposite element
  • Otherwise each element is mapped to every corresponding element
  • Unless a mapping string is provided that specifies sub-dimensions, in which case matching sub-dimensions are mapped N-to-N and the remaining sub-dimensions are mapped N-to-all

The default connection mapping can be substituted with any connection mapping class that implements the IConnectionMapping interface allowing an individual connection to use special mappings such as look-up tables, modulos, offsets etc.

Absolute and relative link numbers

Link numbers transmitted between ProducerConsumers are always relative to the start of the connection. This ensures that a sending task doesn't need to know anything about any other connections that the receiving task owns.

Internally within the ProducerConsumer the array that holds all the link state uses absolute indexing because it is more efficient to allocate a single block of memory that holds the information for all of the connections and the state processing generally isn't concerned with the grouping of links into connections so it is more efficient to process them as a flat array of links.

This requires a translation between relative and absolute link numbering at the point where events are transmitted/received.

The API for ProducerConsumer specializations

Specializations of ProducerConsumer subscribe to various events to add operator-specific processing on a query/event/release/released message arrival. The event handler is passed relevant information such as the absolute link number, the consumer and producer slot IDs, the slot store, the state associated with the receiving task element and the element number and can then perform particular processing that implements its specific operation.

If the specialized ProducerConsumer task does not subscribe to a particular event then it is not triggered.

Last edited Oct 7, 2012 at 10:03 AM by jaorme, version 10


No comments yet.