Pattern Name: AsynchronousComposition |
AlgorithmStructure Design Space |
This pattern describes what may be the most loosely structured type of concurrent program, in which semi-independent tasks interact through asynchronous events.
Some problems are most naturally represented as a collection of semi-independent entities interacting in an irregular way. Examples of such problems include the following:
Next we show a sample execution sequence for two of the tasks, to illustrate the interaction.
For such problems, it often makes sense to base a parallel algorithm on defining a task for each of the entities (or possibly a group of tasks, if a hierarchical design makes sense). Interaction between these tasks is then based on ordering constraints (e.g., "this calculation in task A must happen before that calculation in task B").
Use this pattern when:
This pattern is particularly appropriate when:
Implementations of this pattern include the following key elements:
This pattern is typically used to provide high-level structure for an application; that is, the application is typically structured as an instance of this pattern.
What is needed here is a program structure to hold the computations associated with the tasks/entities. This is essentially the same as the problem of defining the pipeline elements in the PipelineProcessing pattern, and the same approaches apply.
What is needed here is a mechanism for representing the interaction among tasks/entities. If the interaction is in terms of events, what is needed is a way for the task generating the event to communicate it to the task that will process it. In a shared-memory environment, this can be done via a shared queue data structure (which can be implemented with the SharedQueue pattern), with the generating task adding items to the queue and the processing task removing and processing them. In a message-passing environment, an event corresponds to a message sent from the generating task to the processing task.
What is needed here is a way of scheduling the tasks or task groups that make up the design. It is simplest to schedule all tasks to execute concurrently (as in the PipelineProcessing pattern), since this makes it easier to avoid deadlock.
Examples to be added soon.
Known uses of this pattern are in event-driven programming and discrete event simulation.
This pattern is similar to the PipelineProcessing pattern in that both patterns apply to problems where it is natural to decompose the computation into a collection of semi-independent entities. The difference is that in the PipelineProcessing pattern, these entities interact in a more regular way, with all "stages" of the pipeline proceeding in a loosely synchronous way, whereas in the AsynchronousComposition pattern, there is no such requirement, and the entities can interact in very irregular and asynchronous ways.