|Ada 95 Quality and Style Guide||Chapter 6|
Consider using discriminants to minimize the need for an explicit initialization operation (Rationale 1995, §9.1).
Consider using discriminants to control composite components of the protected objects, including setting the size of an entry family (Rationale 1995, §9.1).
Consider using a discriminant to set the priority of a protected object (Rationale 1995, §9.1).
Consider using a discriminant to identify an interrupt to a protected object (Rationale 1995, §9.1).
Consider declaring a task type with a discriminant to indicate (Rationale 1995, §9.6):
- - Priority, storage size, and size of entry families of individual tasks of a type
- - Data associated with a task (through an access discriminant)
The following code fragment shows how a task type with discriminant can be used to associate data with a task (Rationale 1995, §9.6):type Task_Data is record ... -- data for task to work on end record; task type Worker (D : access Task_Data) is ... end; -- When you declare a task object of type Worker, you explicitly associate this task with -- its data through the discriminant D Data_for_Worker_X : aliased Task_Data := ...; X : Worker (Data_for_Worker_X'Access);
The following example shows how to use discriminants to associate data with tasks, thus allowing the tasks to be parameterized when they are declared and eliminating the need for an initial rendezvous with the task:task type Producer (Channel : Channel_Number; ID : ID_Number); task body Producer is begin loop ... -- generate an item Buffer.Put (New_Item); end loop; end Producer; ... Keyboard : Producer (Channel => Keyboard_Channel, ID => 1); Mouse : Producer (Channel => Mouse_Channel, ID => 2);
The next example shows how an initial rendezvous can be used to associate data with tasks. This is more complicated and more error prone than the previous example. This method is no longer needed in Ada 95 due to the availability of discriminants with task types and protected types:task type Producer is entry Initialize (Channel : in Channel_Number; ID : in ID_Number); end Producer; task body Producer is IO_Channel : Channel_Number; Producer_ID : ID_Number; begin accept Initialize (Channel : in Channel_Number; ID : in ID_Number) do IO_Channel := Channel; Producer_ID := ID; end; loop ... -- generate an item Buffer.Put (New_Item); end loop; end Producer; ... Keyboard : Producer; Mouse : Producer; ... begin ... Keyboard.Initialize (Channel => Keyboard_Channel, ID => 1); Mouse.Initialize (Channel => Mouse_Channel, ID => 2); ...
Using discriminants to parameterize protected objects provides a low-overhead way of specializing the protected object. You avoid having to declare and call special subprograms solely for the purpose of passing this information to the protected object.
Task discriminants provide a way for you to identify or parameterize a task without the overhead of an initial rendezvous. For example, you can use this discriminant to initialize a task or tell it who it is (from among an array of tasks) (Rationale 1995, §II.9). More importantly, you can associate the discriminant with specific data. When you use an access discriminant, you can bind the data securely to the task because the access discriminant is constant and cannot be detached from the task (Rationale 1995, §9.6). This reduces and might eliminate bottlenecks in the parallel activation of tasks (Rationale 1995, §9.6).
Using an access discriminant to initialize a task has a potential danger in that the data being referenced could change after the rendezvous. This possibility and its effects should be considered and, if necessary, appropriate actions taken (e.g., copy the referenced data and not rely on the data pointed to by the discriminant after initialization).
|< Previous Page||Search||Contents||Index||Next Page >|