Проблемы в Ada Concurrency - PullRequest
       21

Проблемы в Ada Concurrency

2 голосов
/ 22 марта 2010

Мне нужна помощь, а также понимание. Это программа в Аде-2005, которая имеет 3 задачи. Выход «Z». Если 3 задачи не выполняются в порядке их размещения в программе, то выходные данные могут варьироваться от z = 2, z = 1 до z = 0 (это легко увидеть в программе, попытка взаимного исключения пытается убедиться, что выходные данные это z = 2).

WITH Ada.Text_IO; USE Ada.Text_IO;
WITH Ada.Integer_Text_IO; USE Ada.Integer_Text_IO; 
WITH System; USE System;

procedure xyz is 
   x : Integer := 0; 
   y : Integer := 0; 
   z : Integer := 0;

   task task1 is
      pragma Priority(System.Default_Priority + 3);
   end task1;

   task task2 is
      pragma Priority(System.Default_Priority + 2);
   end task2;

   task task3 is
      pragma Priority(System.Default_Priority + 1);
   end task3;

   task body task1 is
   begin
      x := x + 1;
   end task1;

   task body task2 is
   begin
      y := x + y;
   end task2;

   task body task3 is
   begin
      z := x + y + z;
   end task3;

begin 
   Put(" z = ");
   Put(z); 
end xyz;

Я впервые попробовал эту программу

(а) без прагм, результат: в 100 попытках, вхождение 2: 86, вхождение 1: 10, вхождение 0: 4.

Тогда

(b) с прагмами, результат: в 100 попытках, вхождение 2: 84, вхождение 1: 14, вхождение 0: 2.

Что неожиданно, так как 2 результата почти идентичны. Что означает прагму или отсутствие прагмы, результат имеет то же поведение.

Те, кто являются гуру параллелизма Ады, пожалуйста, пролите немного света на эту тему. Альтернативные решения с семафорами (если это возможно) также предлагается.

Далее, на мой взгляд, для критического процесса (именно так мы поступаем с Ada), с прагмами результат должен быть z = 2, 100% всегда, следовательно, иначе программа должна называться критической 85%! !!! (Это не должно быть так с Ада)

Ответы [ 3 ]

5 голосов
/ 23 марта 2010

Защищенный объект для выполнения трех операций может выглядеть примерно так.Но обратите внимание, что все это делает, чтобы убедиться, что три переменные x, y и z соответствуют порядку, в котором произошли обновления;он ничего не говорит о порядке.

   protected P is
      procedure Update_X;
      procedure Update_Y;
      procedure Update_Z;
      function Get_Z return Integer;
   private
      X : Integer := 0;
      Y : Integer := 0;
      Z : Integer := 0;
   end P;
   protected body P is
      procedure Update_X is
      begin
         X := X + 1;
      end Update_X;
      procedure Update_Y is
      begin
         Y := Y + X;
      end Update_Y;
      procedure Update_Z is
      begin
         Z := X + Y + Z;
      end Update_Z;
      function Get_Z return Integer is
      begin
         return Z;
      end Get_Z;
   end P;

С другой стороны, чтобы убедиться, что три задачи «представляют свои результаты» в правильном порядке, вы можете переписать P так, чтобы вызов с именем Update_Yблокировать до вызова Update_X: теперь Get_Z должен быть записью с выходным параметром, а не функцией.

  protected P is
      entry Update_X;
      entry Update_Y;
      entry Update_Z;
      entry Get_Z (Result : out Integer);
   private
      X_Updated : Boolean := False;
      Y_Updated : Boolean := False;
      Z_Updated : Boolean := False;
      X : Integer := 0;
      Y : Integer := 0;
      Z : Integer := 0;
   end P;
   protected body P is
      entry Update_X when True is
      begin
         X := X + 1;
         X_Updated := True;
      end Update_X;
      entry Update_Y when X_Updated is
      begin
         Y := Y + X;
         Y_Updated := True;
      end Update_Y;
      entry Update_Z when Y_Updated is
      begin
         Z := X + Y + Z;
         Z_Updated := True;
      end Update_Z;
      entry Get_Z (Result : out Integer) when Z_Updated is
      begin
         Result := Z;
      end Get_Z;
   end P;

Теперь три задачи могут иметь любой приоритет.Но задача, которая вызывает Update_Z, будет блокироваться до тех пор, пока две другие не сообщат.

1 голос
/ 23 марта 2010

Ну, эти прагмы просто устанавливают приоритеты задач в вашей системе, они не гарантируют какого-либо взаимного исключения этих переменных.

Там может быть некоторыми системами, где этодовольно.Однако большинство реализаций Ada в наши дни отображают задачи Ada в потоки ОС, а большинство потребительских ПК в наши дни имеют несколько процессоров и могут распределять свои потоки между ними.Ничто не мешает ОС планировать следующий поток с более низким приоритетом на вашем втором процессоре, пока выполняется поток с наивысшим приоритетом.

Такой тип поведения в программе называется «условием гонки».

Если вы хотите взаимоисключения по этим переменным, вам необходимо реализовать это.Либо предоставьте контроль над переменными одной задаче и используйте рандеву, чтобы изменить их из других задач, либо изучите возможность помещения их в защищенных объектов .Я бы предложил последнее, так как рандеву может быть намного сложнее понять правильно.Однако, если вы хотите упорядочить вызовы особым образом, задача главного контроллера, вызывающая рандеву для других задач, может оказаться подходящим вариантом.

0 голосов
/ 25 марта 2010

вот программа, которая является последовательным вариантом выше! .... только с одной задачей (даже этого можно избежать, если я использую одну процедуру, как предложено Марком С. и Т.Д.)

С Ada.Text_IO; USE Ada.Text_IO;

С Ada.Integer_Text_IO; ИСПОЛЬЗОВАНИЕ Ada.Integer_Text_IO;

С системой; ИСПОЛЬЗОВАТЬ систему;

процедура xyzsimple составляет

x: целое число: = 0; y: целое число: = 0; z: целое число: = 0;

тип задачи xyz;

T: xyz;

тело задачи xyz равно

начало

x: = x + 1;
у: = х + у;
z: = x + y + z;

end xyz;

begin Put ("z =");

Помещенный (г);

конец xyzsimple;

Эта программа всегда выдает результат z = 2, но тогда она не служит иллюстрацией того, что я пытался сделать. Эта программа является детерминированной, а не парадигмой параллелизма! Кроме того, эта программа никогда не будет демонстрировать «РАСОВОЕ СОСТОЯНИЕ», о котором упоминал Т.Э.

...