1

我在http://en.wikibooks.org/wiki/Ada_Programming/Tasking上阅读了一些关于 ada 中的任务的内容,并认为我会自己写一些关于任务的小东西。因为我最近读了一个关于 Pintos 的小课程,所以我想我会实现一个小的读写器算法。这是我的尝试:

procedure Test_Queue is

   type Int_Array is array(1..10) of Integer;

   task type Queue is
      entry Quit;
      entry Pop(Elem : out Integer);
      entry Push(Elem : in Integer);
   end Queue;

   task body Queue is
      Elems_In_Queue : Integer := 0;
      Q : Int_Array;
   begin
      loop
         select
            accept Push(Elem : in Integer) do
               Put_Line("Push");
               Elems_In_Queue := Elems_In_Queue + 1;
               Q(Elems_In_Queue) := Elem;
            end Push;
         or
            when Elems_In_Queue > 0 =>
               accept Pop(Elem : out Integer) do
                    Put_Line("Pop");
                Elem := Q(Elems_In_Queue);
                Elems_In_Queue := Elems_In_Queue - 1;
               end Pop;
         else
            delay 1.0;
            Put_Line("Waited");
            accept Quit;
            exit;
         end select;
      end loop;
      Put_Line("Got out of the loop");
   end Queue;

   Q : Queue;
   X : Integer;

begin
   Put_Line("Started");
   Q.Push(10);
   Put_Line("Pushed");
   Q.Push(11);
   Put_Line("Pushed");
   Q.Pop(X);
   Put_Line("Integer:" & Integer'Image(X));
   Q.Quit;
   Put_Line("Done");
end Test_Queue;

可能值得一提的是,我希望看到的行为是,当 1 秒内没有对队列/堆栈进行任何操作(推送/弹出)时,我希望任务终止/退出无限循环。

But this just outputs "Started" and then goes to my delay 1.0 and outputs "Wait". This is not exactly what I expected since i have accept for at least push and that is the first thing i call. Where have i been thinking wrong and why doesn't this work? Also, are there any more sources with some examples as for how to do tasking in Ada? I managed to implement this by creating a Semaphore and Lock in 2 different tasks but that seemed to be a bad solution and not very adaesque.

4

1 回答 1

4

Having improved the diagnostics, it is clear that on startup, neither of the Select alternatives was immediately available so the Queue task was going straight to the Else part, and after 1 second delay, waiting to accept Quit.

Meanwhile the main task was blocking on its first (unconditional, untimed!) Push entry call, so that it could never issue the Quit entry call. Result : Deadlock.

The solution (described in Burns & Welling on p.108) is simply to change ELSE to OR so that the third (Delay) option is still a Select alternative. Then in each iteration, the earliest of (Push, Pop or Delay) will be accepted.

于 2013-03-30T11:55:16.237 回答