我已经在http://en.wikibooks.org/wiki/Ada_Programming/Tasking上阅读了有关ada中的任务的一些内容,并认为我会自己编写一些有关任务的东西。由于我最近读过Pintos上的一门小类(class),所以我认为我会实现一些读者-作家算法。这是我的尝试:
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秒钟内未对队列/堆栈进行任何操作(插入/弹出)时,我希望任务终止/退出无限循环。
但这只是输出“开始”,然后转到我的延迟1.0并输出“等待”。这并不是我所期望的,因为我至少接受了推送,这是我首先要说的。我在哪里想错了,为什么这行不通?此外,是否还有其他示例中有关如何在Ada中执行任务的资源?我设法通过在2个不同的任务中创建信号量和锁定来实现此目的,但这似乎是一个糟糕的解决方案,而且不是很老套。
最佳答案
在改进诊断程序之后,很明显,在启动时,没有Select
替代方案都立即可用,因此Queue任务直接进入Else
部分,并在延迟1秒后等待接受Quit
。
同时,主要任务是阻止其第一个(无条件,不定时!)Push
入口调用,因此它永远不会发出Quit
入口调用。结果:死锁。
解决方案(在第108页的Burns & Welling中描述)只是将ELSE
更改为OR
,以便第三个(延迟)选项仍然是Select
的替代方案。然后,在每次迭代中,最早的(Push,Pop或Delay)将被接受。
关于multithreading - Ada任务和终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15716699/