Ada 并发问题

发布于 2024-08-26 02:50:06 字数 1202 浏览 4 评论 0原文

我需要一些帮助,也需要一些见解。这是 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;

我第一次尝试这个程序

(a)没有编译指示,结果:在100次尝试中,出现2:86,出现1:10,出现0:4。

然后

(b)使用编译指示,结果:在100次尝试中,出现 2: 84、出现 1: 14、出现 0: 2。

这是出乎意料的,因为 2 个结果几乎相同。这意味着无论是否有编译指示,输出都具有相同的行为。

Ada 并发大师请阐明这个主题。还邀请使用信号量的替代解决方案(如果可能)。

此外,我认为对于关键过程(这就是我们对 Ada 所做的),使用编译指示时,结果应该是 z = 2,始终为 100%,因此或以其他方式,该程序应被称为 85% 关键! (艾达不应该这样)

I need some help and also some insight. This is a program in Ada-2005 which has 3 tasks. The output is 'z'. If the 3 tasks do not happen in the order of their placement in the program then output can vary from z = 2, z = 1 to z = 0 ( That is easy to see in the program, mutual exclusion is attempted to make sure output is 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;

I first tried this program

(a) without pragmas, the result : In 100 tries, occurence of 2: 86, occurence of 1: 10, occurence of 0: 4.

Then

(b) with pragmas, the result : In 100 tries, occurence of 2: 84, occurence of 1 : 14, occurence of 0: 2.

Which is unexpected as the 2 results are nearly identical. Which means pragmas or no pragmas the output has same behavior.

Those who are Ada concurrency Gurus please shed some light on this topic. Alternative solutions with semaphores (if possible) is also invited.

Further in my opinion for a critical process (that is what we do with Ada), with pragmas the result should be z = 2, 100% at all times, hence or otherwise this program should be termed as 85% critical !!!! (That should not be so with Ada)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

假扮的天使 2024-09-02 02:50:06

执行这三个操作的受保护对象可能看起来像这样。但请注意,这只是确保三个变量 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 现在必须是带有out 参数而不是函数。

  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 的任务将阻塞,直到其他两个任务报告为止。

A protected object to do the three operations might look something like this. But note, all this does is make sure that the three variables x, y and z are consistent with the order that the updates occurred in; it says nothing about the order.

   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;

On the other hand, to make sure that the three tasks "submit their results" in the proper order, you could rewrite P so that a call to say Update_Y will block until Update_X has been called: Get_Z now has to be an entry with an out parameter rather than a function.

  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;

The three tasks can now have any priority you like. But the task that calls Update_Z will block until the other two have reported.

合久必婚 2024-09-02 02:50:06

好吧,这些编译指示只是优先考虑系统上的任务,它们不保证这些变量的任何类型的互斥。

可能在某些系统中这就足够了。然而,现在大多数 Ada 实现都将 Ada 任务映射到操作系统线程,并且现在大多数消费者 PC 都具有多个处理器,并且可以在其中溢出线程。当最高优先级线程正在运行时,没有什么可以阻止操作系统在第二个处理器上调度下一个较低优先级线程。

程序中的这种行为称为“竞争条件”。

如果你想对这些变量进行互斥,你需要实现它。要么将变量的控制权交给一个任务,然后使用集合点从其他任务中修改它们,要么考虑将它们放入 受保护的对象。我建议后者,因为约会可能更难找到正确的地点。但是,如果您想以特定方式对调用进行排序,则可以使用主控制器任务来调用其他任务上的集合点。

Well, those pragmas just prioritize the tasks on your system, they don't guarantee any kind of mutual-exclusion on those variables.

There may be some systems where that is enough. However, most Ada implementations these days map Ada tasks to OS threads, and most consumer PC's these days have multiple processors and can spilt their threads among them. There's nothing stopping the OS from scheduling the next lower-priority thread on your second processor while the highest priority thread is running.

This kind of behavior in a program is called a "race condition".

If you want mutual-exlusion on those variables, you need to implement that. Either give control of the variables to one task and use rendezvous to modify them from other tasks, or look into putting them into protected objects. I'd suggest the latter, as rendezvous can be much more difficult to get right. However, if you want to order the calls in a specific way, a master controller task calling rendezvous on the other tasks might be the way to go.

痞味浪人 2024-09-02 02:50:06

这是一个程序,它是上述程序的顺序变体! ....仅执行一项任务(即使按照 Marc C 和 TED 的建议,如果我使用单个程序,也可以避免这种情况)

使用 Ada.Text_IO;使用 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;
y:= x + y;
z:= x + y + z;

结束xyz​​;

开始 Put(" z = ");

放置(z);

结束xyz​​simple;

这个程序总是输出 z = 2,但是它并不能说明我想要做什么。这个程序是确定性的,不属于并发范式!此外,这个程序永远不会表现出 TED 提到的“RACE CONDITION”。

here is a program that is a sequential variant of the above ! .... with just one task (even that can be avoided if I use a single procedure, as suggested by Marc C and T.E.D )

WITH Ada.Text_IO; USE Ada.Text_IO;

WITH Ada.Integer_Text_IO; USE
Ada.Integer_Text_IO;

WITH System; USE System;

procedure xyzsimple is

x : Integer := 0;
y : Integer := 0;
z : Integer := 0;

task type xyz;

T: xyz;

task body xyz is

begin

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

end xyz;

begin Put(" z = ");

Put(z);

end xyzsimple;

This program always gvies output z = 2, but then it doesn't serve to illustrate what I was trying to do. This program is deterministic, not into the paradigm of concurrency ! Further, this program will never exhibit 'RACE CONDITION' that T.E.D had mentioned.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文