Task Design Pattern
Realtime systems are generally designed as a sequence of message interactions between tasks. This article describes different types of task design patterns.
The most common task design patterns are:
|Threads and Tasks|
|Most modern operating systems provide a separate data space to every task. The data space for every task is protected from illegal access from other tasks. Most tasks execute a single sequence of instructions. This is commonly referred to as a single thread. Complex tasks however might be implemented with multiple threads of execution within the same data space, this is commonly referred to as multi-threaded programming. Two threads running in a single task can access the same data as both of them are running in the same data space.|
A simple task is composed of a single state machine handled by the only thread in the task. Messages received by the task are dispatched to the currently active state. In such tasks the state machine state and task state are one.
Here, a single task manages many state machines within a single thread of execution. Messages received by the task are first dispatched to the appropriate state machine. The messages are further routed to the appropriate state of the state machine. Since the task is single threaded, the next message can be dispatched only after the processing of the current message has been finished.
Multi Threaded Manager
A multi threaded manager task manages many state machines, each state machine handled in a separate thread. Messages received by the task are first dispatched to the appropriate thread. The message is then handled in the appropriate thread's state machine. Here, the next message can be dispatched immediately after dispatching the current message since the message handling is taken care by a separate thread.
Multi Task Manager
Multi Task Manager is similar to the Multi Thread Manager. The main difference is that the managed state machines are in different tasks, thus no data can be shared between state machines. Messages are the only means of communication and synchronization.
Different Task Design Patterns are compared for different attributes in the following matrix:
|Simple Task||Single Threaded Manager||Multi Threaded Manager||Multi Task Manager|
|Complexity||Simple. A single state machine has to be handled.||More complicated as state machine creation, deletion and message dispatching have to be managed.||More complicated than Single Threaded Manager as thread concurrency issues need to be addressed when sharing data.||Most complicated as all communication has to be managed via messages.|
|Message Routing||Simple. Messages just need to be routed to the current state's handler.||More Complicated. Message needs to be dispatched to the appropriate state machine object. All the state machines share a single message queue, so the dispatching overhead will be incurred for every message exchange||Complicated. Initial messages need to be dispatched to the thread handling the state machine. Subsequent messages might be received directly by the thread.||Most complicated. Initial messages need to be dispatched by the task managing the state machines. Subsequent messages will be received directly by the task.|
|Heap and Stack||A single heap and stack is used.||All state machines share a single heap and stack.||All state machine threads share a single heap. Each thread has its own stack.||All state machine tasks have their own stack and heap.|
|Reliability||Reliable. Heap and stack are not shared.||Low Reliability. Crash in a single state machine will cause the entire task to crash. Stack and heap corruption will affect all state machines.||Medium Reliability. Crash in a single state machine thread will have minimal impact on other threads. Corruption of a thread's stack will only impact that thread. Heap corruption, overflow however will impact the complete task. Memory wild writes by one state machine can impact the complete task.||High Reliability. Each state machine has its own stack and heap. Memory wild writes in one task will have no impact on the other task.|
|Means of Communication||Messaging and memory access.||Messaging and memory access.||Messaging and memory access. Memory access however needs to take care of concurrency.||Messaging only.|
|Performance||High.||High. As a single thread with a single stack is used. This gives a better locality of reference on the processor cache.||Medium. Thread switching overheads lower performance. Poorer locality of reference due to separate stacks.||Low. Task switching overheads are much higher than thread switching overheads. Poorest locality of reference as a separate stack and heap are used for every task.|
|Multi- processor Scalability||None. Complete execution is in a single thread so performance of this task cannot be improved by adding processors.||None. Complete execution is in a single thread so performance of this task cannot be improved by adding processors.||Medium. Each state machine is implemented as a separate thread, so adding more processors will allow multiple threads to run concurrently on different processors. Heap contention will however limit scalability.||High. Tasks have their individual threads, stacks and heaps. No resources are shared between different tasks so the system will scale well with addition of processors.|