Question

So i've got code like this:

task body Task1Type is
begin
    Put_Line("Task1 Part1");
    Task2.Part1Ready;
    accept Part1Ready;
    Put_Line("Task1 Part2");
end;

task body Task2Type is
begin
    Put_Line("Task2 Part1");
    Task1.Part1Ready;
    accept Part1Ready;
    Put_Line("Task2 Part2");
end;

My logic tells me that part2 in every task must run after both tasks completed task1. But it doesn't. Where I'm wrong?

Was it helpful?

Solution

When Task1 calls Task2.Part1Ready, it blocks until Task2 issues accept Part1Ready. Likewise, when Task2 calls Task1.Part1Ready, it blocks until Task1 issues accept Part1Ready.

This is known as a ‘deadly embrace', and means that neither task can proceed. One way round this is to use a protected object, perhaps like this:

protected Readiness is
   procedure Task_1_Ready;
   entry Wait_Until_Task_1_Ready;

   procedure Task_2_Ready;
   entry Wait_Until_Task_2_Ready;
private
   Task_1_Is_Ready : Boolean := False;
   Task_2_Is_Ready : Boolean := False;
end Readiness;

protected body Readiness is
   procedure Task_1_Ready is
   begin
      Task_1_Is_Ready := True;
   end Task_1_Ready;

   entry Wait_Until_Task_1_Ready when Task_1_Is_Ready is
   begin
      null;
   end Wait_Until_Task_1_Ready;

   procedure Task_2_Ready is
   begin
      Task_2_Is_Ready := True;
   end Task_2_Ready;

   entry Wait_Until_Task_2_Ready when Task_2_Is_Ready is
   begin
      null;
   end Wait_Until_Task_2_Ready;
end Readiness;

Then get rid of the Part1Ready task entries, replacing

task body Task1Type is begin
   Put_Line("Task1 Part1");
   Task2.Part1Ready;
   accept Part1Ready;
   Put_Line("Task1 Part2”);
end;

with

task body Task1Type is begin
   Put_Line("Task1 Part1");
   Readiness.Task_1_Ready;
   Readiness.Wait_Until_Task_2_Ready;
   Put_Line("Task1 Part2”);
end;

and vice-versa in Task2Type.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top