Ada并发中的问题

Ark*_*avo 2 concurrency ada pragma

我需要一些帮助,也需要一些见解.这是Ada-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;
Run Code Online (Sandbox Code Playgroud)

我第一次尝试这个程序

(a)没有pragma,结果:在100次尝试中,出现2:86,出现1:10,出现0:4.

然后

(b)用pragma,结果:在100次尝试中,出现2:84,出现1:14,出现0:2.

这是意料之外的,因为2结果几乎相同.这意味着编译指示或没有编译指示输出具有相同的行为.

那些Ada并发大师们请谈谈这个话题.还邀请了具有信号量的替代解决方案(如果可能的话).

在我看来,对于一个关键过程(也就是我们用Ada做的事情),对于pragma,结果应该始终为z = 2,100%,因此或者该程序应该被称为85%的关键!!!! (Ada不应该这样)

Sim*_*ght 5

执行这三个操作的受保护对象可能看起来像这样.但请注意,所有这一切都是为了确保三个变量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;
Run Code Online (Sandbox Code Playgroud)

另一方面,为了确保三个任务以正确的顺序"提交结果",您可以重写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;
Run Code Online (Sandbox Code Playgroud)

这三项任务现在可以优先考虑.但调用Update_Z的任务将阻塞,直到其他两个报告.