Quick introduction to Ada tasking

Document Sample
Quick introduction to Ada tasking Powered By Docstoc
					Concurrent Programming
using Ada Tasking

               CS 472 Operating Systems
    Indiana University – Purdue University Fort Wayne
                        Mark Temte

Quick introduction to Ada tasking

 Ada program units   Java equivalent
 procedure           void method
 function            non-void method
 package             class
 task                subclass of Thread class
 generic unit        type parameters (J2SE, version 1.5)

Most Ada units are separated into a
specification and a body
 Specifications are not always required for
 procedures and functions
 When needed, these specifications consist of the
 procedure or function “signature” followed by a “;”
 The corresponding body consists of the signature
 followed by “is” followed by declarations and a
 “begin-end” section

Generic units
 An Ada generic unit is a parameterized template for
 an actual procedure, function, or package
 Java and generic classes
    Prior to J2SE, Version 1.5, Java had no direct equivalent,
    except possibly for inheritance and interfaces
    J2SE, Version 1.5, supports type parameters
         Type parameters permit implementation of generic classes
    E is a type parameter in the following example
public class LinkedList< E > implements Collection< E > ● ● ●

LinkedList<Employee> empList = new LinkedList<Employee>( );
Example of an Ada procedure
 with Ada.Text_IO; -- makes library package Text_IO visible
                       -- procedures Get and Put are now available
 procedure Fibonacci is
   type Fib_Num_Type is range 0..10_000;             -- declares a type
   Fib              : Fib_Num_Type := 1;             -- declares three variables
   Prev_Fib         : Fib_Num_Type := 0;             -- and initializes the
   Next_Prev_Fib : Fib_Num_Type;                     --    first two
   -- The following instantiates a gereric package to perform I/O with
   -- values of type Fib_Num_Type.
   package Fib_IO is new Ada.Text_IO.Integer_IO( Fib_Num_Type );
 begin -- Fibonacci
   Ada.Text_IO.Put( "Fibonacci numbers follow:" ); -- output by procedures in
   Ada.Text_IO.New_Line( Spacing => 2 );                -- Text_IO package
   Fib_IO.Put( Prev_Fib );         -- output by procedure in Fib_IO
   Fib_IO.Put( Fib );              -- output by procedure in Fib_IO
   for Index in 2..25 loop
      Next_Prev_Fib := Prev_Fib;
      Prev_Fib := Fib;
      Fib       := Prev_Fib + Next_Prev_Fib;
      Fib_IO.Put( Fib );
   end loop;
 exception -- exception handler for the situation where Fib > 10_000.
   when Constraint_Error =>
      Ada.Text_IO.Put( "Exception raised: Fibonacci value out of bounds." );
 end Fibonacci;

An Ada task …
 is a thread within an Ada application
   It may not stand alone
   It must be nested within a “master”
   The master is typically a procedure
 starts executing automatically when master
 consists of a specification and a body
 communicates and synchronizes with other
 tasks using a simple high-level rendezvous

An Ada task …
 is relatively easy to demonstrate to be correct
 has task states
   Ready – unblocked waiting for a processor
   Blocked – delayed or waiting to rendezvous
   Completed – at “end”
   Terminated – no longer active

Example of nesting tasks in a procedure
  procedure Master is
    task A;              -- specification for A
    task B;              -- specification for B
    task body A is …; -- body of A
    task body B is …; -- body of B
  begin -- Master
    null; -- tasks A and B begin execution
  end Master;

Format of a task body
(similar to the body of a procedure)
   task body A is
   begin -- A
   exception -- this section is optional
   end A;

Task type
A task type is a template for an actual task

Many actual tasks may be created from the template.

  task type TypeT;      -- specification of task type
  task body TypeT is …; -- body

  T1 : TypeT; -- declaration of an actual task T1
  T2 : TypeT; -- declaration of another actual task T2

A task type may be parameterized
 with Ada.Text_IO;
 procedure Two_Tasks is
  task type SimpleTask (Message: Character; HowMany: Positive);
  task body SimpleTask is
  begin -- SimpleTask
    for Count in 1..HowMany loop
      Ada.Text_IO.Put("Hello from Task " & Message);
    end loop;
  end SimpleTask;
  Task_A: SimpleTask(Message => 'A', HowMany => 5);
  Task_B: SimpleTask(Message => 'B', HowMany => 7);
 begin -- Two_Tasks
  -- Task_A and Task_B will both start executing as soon as control
  -- reaches this point, before any of the main program's
  -- statements are executed. The Ada standard does not specify
  -- which task will start first.
 end Two_Tasks;

Rendezvous basics
 Tasks communicate using a rendezvous
 Exactly two tasks may rendezvous a a time
   a caller
   a server
 The server must have an entry declared in its
 An entry resembles a procedure specification
 An entry may be called whenever a procedure may
 be called
 An entry call resembles a procedure call
Rendezvous basics
 Entries (and calls) may involve parameters for
   As in the case of procedures, parameters may have
   modes in, out and in out
 No parameters are needed just for synchronization
 A server task accepts a call to its entry using an
 accept statement
 The caller must know the names of the server’s
 entries, but the server does not know the caller

Rendezvous basics
   caller task   server task





Example - An entry is used just for synchronization
with Ada.Text_IO;
procedure Start_Buttons is
 task type SimpleTask (Message: Character; HowMany: Positive) is
    entry StartRunning;
 end SimpleTask;
 task body SimpleTask is
 begin -- SimpleTask
   accept StartRunning;
   for Count in 1..HowMany loop
     Ada.Text_IO.Put(Item => "Hello from Task " & Message);
     delay 0.1; -- Lets another task have the CPU
                -- Note: delay is NOT a good way to do this!
   end loop;
 end SimpleTask;
 Task_A: SimpleTask(Message => 'A', HowMany => 5);
 Task_B: SimpleTask(Message => 'B', HowMany => 7);
 Task_C: SimpleTask(Message => 'C', HowMany => 4);
begin -- Start_Buttons
end Start_Buttons;

Rendezvous semantics
 If one task gets to the rendezvous point (either a
 call or an accept) in its code before the other, it
 waits until the other task arrives
 During execution of an accept statement within a
 server task (the actual rendezvous), the caller
 At the conclusion, both tasks may resume

Rendezvous semantics
 Execution of an accept statement serves a
 single call
   This insures access to the server’s data under
   mutual exclusion
 Callers to an entry must wait in a FIFO queue
   Attribute Name’Count gives the number of callers
   waiting on entry Name

Example of a task used to represent a stack
This involves a task specification with entries and parameters

      task Stack is
        entry Push( Value : in Integer);
        entry Pop( Value : out Integer);
      end Stack;

  A call to Push within some caller task looks like:

        
      Stack.Push( 23);
        
Format of “accept” statement within Stack task

  accept Push( Value : in Integer ) do
    <activity done under mutual exclusion>
  end Push;

  Activity done under mutual exclusion should be
  kept to a minimum

The body of Stack task
 task body Stack is
    type ArrayType is array( 1 .. 100 ) of Integer;
    S : ArrayType;
    Top : Natural := 0;
 begin – Stack
        
      accept Push( Value : in Integer )
         Top       := Top + 1;
         S( Top ) := Value;
      end Push;
        
    end loop;
 end Stack;

Selective wait statement
 The selective wait statement allows the server
 to control the acceptance of entry calls
 It may appear within a server task

Format of selective wait statement
      when <condition1> =>      -- a guard
         accept A(    ) do
         end A;
 or                             -- no guard; alternative always open
      accept B(    ) do
      end B;
      when <condition2> =>      -- another guard
         accept C(    ) do
         end C;
 -- the boxed items are optional choices (choose at most one)

 else                          or                         or
   <seq. of stmts>               delay 10.0;                   terminate;
                                 <seq. of stmts>
 end select;

Selective wait semantics
 Guard conditions are evaluated at the top of the
 select statement
 A select alternative is open if a guard is true or if
 there is no guard
 An optional else-part is evaluated only if no
 pending calls exist to any open alternatives
 If there is no else-part and there are no pending
 calls to open alternatives, the server waits

Selective wait semantics
 If pending calls exist to several open
 alternatives, a “fair” selection is made
 With a delay alternative, the sequence of
 statements is executed only if no rendezvous
 has occurred by the delay time
 A terminate alternative takes effect only if all
 other tasks (and parent task) are waiting at end
 or terminate
   In this case all terminate together
 No else-part is permitted with delay or
 terminate alternatives                             24
Example involving the Stack task
       accept Push(    ) do
       end Push;
       accept Pop(    ) do
       end Pop;
   end select;
 end loop;
More on delay and select
 Another use of the delay statement is for a task
 to preempt itself with, say, delay 0.1;
 This can be useful when the Ada run-time
 system does not use pre-emption (i.e., no time
 slicing) and allows each task to run until it blocks
 The select statement is also used for
 conditional and timed entry calls on the part of
 the caller

Format for conditional and timed entry calls
    Stack.Pop( Item );
    <other statememts>
 -- one choice required below
 else                    or
     <seq. of stmts>       delay 10.0;
                           <seq. of stmts>

 end select;

Conditional and timed entry call semantics
 A conditional entry call uses the reserved word
 else and a timed entry call uses the reserved
 words or delay
 The else-part of a conditional entry call is
 executed if an entry call is not accepted by the
 server immediately

Conditional and timed entry call semantics
 For a timed entry call, the delay alternative is
 executed if an entry call is not accepted by the
 delay time
 If either an else-part or a delay alternative is
 executed, the associated entry call is cancelled
 and the caller may continue
    Also, the ‘Count attribute is decremented

Example involving the Stack task

   Stack.Push( 23);
 end loop;

Common output problem
 Suppose several tasks need to call procedure Write
   It is necessary to prevent separate output sequences
   from being mixed together
   Thus, each call to Write must be allowed to finish before
   the next call is accepted
 A simple solution is desirable
   It is better to avoid the overhead of running another task

Protected type
 To accomplish the goal, use a protected type to
 enclose the Write procedure
 The protected type implements a simple “monitor”
 for mutual exclusion
   Prevents the “race condition”

protected type Manager is
    procedure Write(…);
end Manager;
protected body Manager is
    procedure Write(   ) is
    end Write;
end Manager;
PrintManager : Manager;
-- declares a protected object managing access to the Write procedure

Example (continued)
 Now tasks TaskA and TaskB do not interleave
 their output

 TaskA                        TaskB
                           
 PrintManager.Write(   )   PrintManager.Write(   )
                           

Protected type semantics
 The protected type guarantees that each call to
 a protected procedure will complete before
 another call can be started
 If there are several procedures within the same
 protected object, a call to any of them must
 complete before a call to any other is allowed to


Shared By: