1. -- 
  2. --  Uwe R. Zimmer, Australia, September 2011 
  3. -- 
  4.  
  5. with Ada.Text_IO; use Ada.Text_IO; 
  6.  
  7. with Id_Generator_Sequential; 
  8.  
  9. procedure Synchronize_Task_Groups is 
  10.  
  11.    type Task_Range is new Positive range 1 .. 10; 
  12.  
  13.    package Id_Generator is new Id_Generator_Sequential (Task_Range); 
  14.    use Id_Generator; 
  15.  
  16.    -- 
  17.  
  18.    type Release_Type is (Release_Immediately, Wait_For_Trigger); 
  19.  
  20.    protected Synchronizer is 
  21.  
  22.       entry Synchronize_All_Tasks (Release : Release_Type); 
  23.       entry Wait_For_All_Tasks; 
  24.  
  25.       procedure Trigger; 
  26.  
  27.    private 
  28.       entry Wait_For_Trigger_Condition; 
  29.  
  30.       Release_Tasks, 
  31.       Tasks_Complete, 
  32.       Triggered       : Boolean := False; 
  33.    end Synchronizer; 
  34.  
  35.    -- 
  36.  
  37.    protected body Synchronizer is 
  38.  
  39.       entry Synchronize_All_Tasks (Release : Release_Type) when Synchronize_All_Tasks'Count = Task_Range'Last or else Release_Tasks is 
  40.  
  41.       begin 
  42.          Tasks_Complete := True; 
  43.          Release_Tasks  := Synchronize_All_Tasks'Count > 0; 
  44.          case Release is 
  45.             when Release_Immediately => null; 
  46.             when Wait_For_Trigger    => requeue Wait_For_Trigger_Condition with abort; -- tasks can still bail out 
  47.          end case; 
  48.       end Synchronize_All_Tasks; 
  49.  
  50.       -- 
  51.  
  52.       entry Wait_For_All_Tasks when Tasks_Complete is 
  53.  
  54.       begin 
  55.          Tasks_Complete := Wait_For_All_Tasks'Count > 0; 
  56.       end Wait_For_All_Tasks; 
  57.  
  58.       -- 
  59.  
  60.       procedure Trigger is 
  61.  
  62.       begin 
  63.          Triggered := True; 
  64.       end Trigger; 
  65.  
  66.       -- 
  67.  
  68.       entry Wait_For_Trigger_Condition when Triggered is 
  69.  
  70.       begin 
  71.          Triggered := Wait_For_Trigger_Condition'Count > 0; 
  72.       end Wait_For_Trigger_Condition; 
  73.  
  74.    end Synchronizer; 
  75.  
  76.    -- 
  77.  
  78.    task type Synchronized_Operations (Task_Id : Task_Range := Set_Id); 
  79.  
  80.    -- 
  81.  
  82.    task body Synchronized_Operations is 
  83.  
  84.    begin 
  85.       Put_Line ("Task" & Task_Range'Image (Task_Id) & " initialized"); 
  86.  
  87.       delay Duration (Float (Task_Id)); 
  88.  
  89.       Put_Line ("Task" & Task_Range'Image (Task_Id) & " waiting for others to check in and trigger before starting"); 
  90.  
  91.       Synchronizer.Synchronize_All_Tasks (Wait_For_Trigger); 
  92.  
  93.       Put_Line ("Starting Task" & Task_Range'Image (Task_Id)); 
  94.  
  95.       delay Duration (Float (Task_Id)); 
  96.  
  97.       Put_Line ("Task" & Task_Range'Image (Task_Id) & " waiting for others to check in before terminating"); 
  98.  
  99.       Synchronizer.Synchronize_All_Tasks (Release_Immediately); 
  100.  
  101.       Put_Line ("Stopping Task" & Task_Range'Image (Task_Id)); 
  102.    end Synchronized_Operations; 
  103.  
  104.    -- 
  105.  
  106.    Tasks : array (Task_Range) of Synchronized_Operations; 
  107.  
  108.    -- 
  109.  
  110. begin 
  111.    Synchronizer.Wait_For_All_Tasks; 
  112.  
  113.    Put_Line ("--- All tasks ready ---"); 
  114.  
  115.    delay 3.0; 
  116.  
  117.    Synchronizer.Trigger; 
  118.  
  119.    Put_Line ("--- All tasks starting ---"); 
  120.  
  121.    Synchronizer.Wait_For_All_Tasks; 
  122.  
  123.    Put_Line ("--- All tasks complete ---"); 
  124. end Synchronize_Task_Groups;