Ada 像pthread\u barrier\u wait这样的行为?

Ada 像pthread\u barrier\u wait这样的行为?,ada,multitasking,pthread-barriers,Ada,Multitasking,Pthread Barriers,我试图在Ada中实现一个屏障,它的功能与C的pthread_barrier_wait类似。Ada 2012有Ada.Synchronous_屏障,但在我的系统上不可用(debian lenny上的gnu gnat) 更具体地说,我如何才能让所有等待的任务同时从障碍中释放出来,理想情况下,让其中一个任务做一些特殊的事情,而不使用Ada 2012?下面是一个非常次优的实现。有什么更好的方法 with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Tex

我试图在Ada中实现一个屏障,它的功能与C的pthread_barrier_wait类似。Ada 2012有Ada.Synchronous_屏障,但在我的系统上不可用(debian lenny上的gnu gnat)

更具体地说,我如何才能让所有等待的任务同时从障碍中释放出来,理想情况下,让其中一个任务做一些特殊的事情,而不使用Ada 2012?下面是一个非常次优的实现。有什么更好的方法

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure foobar is
   protected Synchronizer is
      entry Ready_For_Action; -- prepares for tasks to wait at barrier
      entry Wait_For_Release; -- barrier
      -- do work here
      entry Done;             -- signals that all tasks are done
      entry Wait_For_Others;  -- prepares for prepare to wait at barrier
   private
      ready, active: Natural := 0;  
      -- two state variables seem to be needed as entry conditions can't
      --    safely modify the condition variable as that influences wait
      --    state in other tasks
   end Synchronizer;

   NUM_OBJECTS: constant := 3;

   protected body Synchronizer is
      entry Ready_For_Action when active = 0 is
      begin
         ready := ready + 1;
      end Ready_For_Action;
      --
      entry Wait_For_Release when ready = NUM_OBJECTS is
      begin
         active := active + 1;
      end Wait_For_Release;
      --
      entry Done when active = NUM_OBJECTS is
      begin
         ready := ready - 1;
      end Done;
      --
      entry Wait_For_Others when ready = 0 is
      begin
         active := active - 1;
      end wait_for_others;
      --
   end Synchronizer;

   task type Foo(N: Natural);

   task body Foo is
      id: Natural := N;
   begin
      for iter in 1..3 loop
         Synchronizer.Ready_For_Action;
         Synchronizer.Wait_For_Release;
         -- task N doing something special
         if id = 1 then new_line; end if;
         -- do stuff here
         delay 0.1;
         put(id); new_line;
         -- re-sync
         Synchronizer.Done;
         Synchronizer.Wait_For_Others;
      end loop;
   end Foo;
   Task1: Foo(1);
   Task2: Foo(2);
   Task3: Foo(3);
begin
   Null;
end foobar;
程序输出:

$ ./foobar 
  3
  1
  2

  3
  1
  2

  3
  2
  1

也许条目上的“count”属性会很有用-这是您正在寻找的类型吗?使用任务ID让一个人做一些不同的事情似乎是明智的(或者如果它足够不同,您可以创建一个新的任务类型)


这扩展了Leon的答案,以实现所需的功能。它使用单个barrier对象并标记一个任意任务来执行某些特殊操作

编辑:结合Jacob的见解,进一步简化障碍,实现最初的目标

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure bar2 is
   NUM_TASKS: constant := 3;

   protected Barrier is
      entry Wait_For_Release(the_chosen_one: out Boolean);
   private
      released: Boolean := False;
   end Barrier;

   protected body Barrier is
      entry Wait_For_Release(the_chosen_one: out Boolean) 
         when (Released or else Wait_For_Release'count = NUM_TASKS) is
      begin
         the_chosen_one := False;
         if Wait_For_Release'count = NUM_TASKS-1 then
            the_chosen_one := True;
            released := True;
         elsif Wait_For_Release'count = 0 then
            released := False;
         end if;
      end Wait_For_Release;
   end Barrier;

   task type Foo(N: Natural);
   task body Foo is
      id: Natural := N;
      the_chosen_one: Boolean;
   begin
      for iter in 1..5 loop
         Barrier.Wait_For_Release(the_chosen_one);
         if the_chosen_one then
            new_line; 
         end if;
         put(id);     -- do stuff here
      end loop;
   end Foo;

   Task1: Foo(1);
   Task2: Foo(2);
   Task3: Foo(3);
begin
   Null;
end bar2;
样本输出:

$ ./bar 

          1          2          3
          3          1          2
          1          2          3
          1          3          2
          3          2          1

此Ada2012包出现在GCC 4.7中。它肯定出现在GNAT GPL 2015中——我只需下载源代码包并使用它(不过最好将其重命名为
Ada_Synchronous_barries
,以避免编译器混淆)。顺便说一句,您可以通过
gnatls-v
来判断系统上的GNAT版本。@SimonWrite伟大的实用解决方案。gnatls在我的机器上显示4.6+1“count”属性是关键——谢谢。我在下面扩展了您的方法,使用一个单独的屏障和两个循环工作的条目。您可能想看看“使用Ada构建并行、嵌入式和实时应用程序”中的第4.7.2节。由于受保护对象的优先级规则,您不需要两个条目。这是不必要的复杂,因为受保护对象的优先级规则意味着在任何新任务进入队列之前,允许所有等待的任务运行该条目。哦,是的!当我写我的答案时,我完全忘记了内部的进展。
$ ./bar 

          1          2          3
          3          1          2
          1          2          3
          1          3          2
          3          2          1