Ada 95 Quality and Style Guide | Chapter 6 |
6.1.2 Tasksguideline
Use tasks to model selected asynchronous threads of control within the problem domain.
Consider using tasks to define concurrent algorithms.
Consider using rendezvous when your application requires synchronous unbuffered communication. example
The naturally concurrent objects within the problem domain can be modeled as Ada tasks.
-- The following example of a stock exchange simulation shows how naturally -- concurrent objects within the problem domain can be modeled as Ada tasks. ------------------------------------------------------------------------- -- Protected objects are used for the Display and for the Transaction_Queue -- because they only need a mutual exclusion mechanism. protected Display is entry Shift_Tape_Left; entry Put_Character_On_Tape (C : in Character); end Display; protected Transaction_Queue is entry Put (T : in Transaction); entry Get (T : out Transaction); function Is_Empty return Boolean; end Transaction_Queue; ------------------------------------------------------------------------- -- A task is needed for the Ticker_Tape because it has independent cyclic -- activity. The Specialist and the Investor are best modeled with tasks -- since they perform different actions simultaneously, and should be -- asynchronous threads of control. task Ticker_Tape; task Specialist is entry Buy (Order : in Order_Type); entry Sell (Order : in Order_Type); end Specialist; task Investor; ------------------------------------------------------------------------- task body Ticker_Tape is ... begin loop Display.Shift_Tape_Left; if not More_To_Send (Current_Tape_String) and then not Transaction_Queue.Is_Empty then Transaction_Queue.Get (Current_Tape_Transaction); ... -- convert Transaction to string end if; if More_To_Send (Current_Tape_String) then Display.Put_Character_On_Tape (Next_Char); end if; delay until Time_To_Shift_Tape; Time_To_Shift_Tape := Time_To_Shift_Tape + Shift_Interval; end loop; end Ticker_Tape; task body Specialist is ... loop select accept Buy (Order : in Order_Type) do ... end Buy; ... or accept Sell (Order : in Order_Type) do ... end Sell; ... else -- match orders ... Transaction_Queue.Put (New_Transaction); ... end select; end loop; end Specialist; task body Investor is ... begin loop -- some algorithm that determines whether the investor -- buys or sells, quantity, price, etc ... if ... then Specialist.Buy (Order); end if; if ... then Specialist.Sell (Order); end if; end loop; end Investor;Multiple tasks that implement the decomposition of a large, matrix multiplication algorithm are an example of an opportunity for real concurrency in a multiprocessor target environment. In a single processor target environment, this approach may not be justified due to the overhead incurred from context switching and the sharing of system resources.
A task that updates a radar display every 30 milliseconds is an example of a cyclic activity supported by a task.
A task that detects an over-temperature condition in a nuclear reactor and performs an emergency shutdown of the systems is an example of a task to support a high-priority activity.
rationale
These guidelines reflect the intended uses of tasks. They all revolve around the fact that a task has its own thread of control separate from the main subprogram (or environment task) of a partition. The conceptual model for a task is a separate program with its own virtual processor. This provides the opportunity to model entities from the problem domain in terms more closely resembling those entities and the opportunity to handle physical devices as a separate concern from the main algorithm of the application. Tasks also allow naturally concurrent activities that can be mapped to multiple processors within a partition when available.
You should use tasks for separate threads of control. When you synchronize tasks, you should use the rendezvous mechanism only when you are trying to synchronize actual processes (e.g., specify a time-sensitive ordering relationship or tightly coupled interprocess communication). For most synchronization needs, however, you should use protected objects (see Guideline 6.1.1), which are more flexible and can minimize unnecessary bottlenecks. Additionally, passive tasks are probably better modeled through protected objects than active tasks.
Resources shared between multiple tasks, such as devices, require control and synchronization because their operations are not atomic. Drawing a circle on a display might require that many low-level operations be performed without interruption by another task. A display manager would ensure that no other task accesses the display until all these operations are complete.
< Previous Page | Search | Contents | Index | Next Page > |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
TOC | TOC | TOC | TOC | TOC | TOC | TOC | TOC | TOC | TOC | TOC |
Appendix | References | Bibliography |