我想创建一个从文件读取几分钟的任务,而主线程执行其他操作。但是我希望主线程能够轮询任务以查看它是否为“忙”(布尔值)而不会阻塞主线程。
我在这里有一个幼稚的尝试,它确实有效,但是它使Busy标志完全暴露出来,可以由主线程随意切换(这是不安全的)...
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Non_Blocking_Reader_Task (Busy : access Boolean) is
entry Read (Destination : in Natural);
end Non_Blocking_Reader_Task;
task body Non_Blocking_Reader_Task is
begin
loop
select
when not Busy.all =>
accept Read (Destination : in Natural) do
Busy.all := True;
end Read;
for i in 1 .. 50 loop
Put ("."); -- pretend to do something useful
delay 0.1; -- while wasting time
end loop;
Busy.all := False;
end select;
end loop;
end Non_Blocking_Reader_Task;
Reader_Busy_Volatile : aliased Boolean;
Reader : Non_Blocking_Reader_Task (Reader_Busy_Volatile'access);
begin
Put_Line (Reader_Busy_Volatile'Image);
Reader.Read (123);
for i in 1 .. 15 loop
Put_Line (Reader_Busy_Volatile'Image);
delay 0.5;
end loop;
abort Reader;
end Main;
我的第二个想法是创建一个protected type
并在其中隐藏标志和任务,但这是语言所不允许的。
问题
我如何创建一个受保护的“任务繁忙”标志,该标志可以从主线程为只读状态,并且可以从任务中读/写(不会导致主线程阻塞)?
编辑:
解决方案!
我根据@flyx的令人鼓舞的建议修订的(有效的)解决方案:)
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Reader_Task is
entry Read (Destination : in Natural);
entry Join;
entry Ready;
end Reader_Task;
task body Reader_Task is
Dest : Natural;
begin
loop
select
accept Read (Destination : in Natural) do
Dest := Destination;
end Read;
-- we only get here after a Read has been received.
for i in 1 .. 5 loop
Put ("."); -- pretend to do something useful
delay 1.0; -- while wasting time
end loop;
or
accept Join;
or
accept Ready;
or
terminate;
end select;
end loop;
end Reader_Task;
Reader : Reader_Task;
begin
-- first call will not block.
Reader.Read (123);
Put_Line ("MAIN: Reading in progress on second thread");
for i in 1 .. 12 loop
select
-- NON-BLOCKING CALL!
Reader.Ready; -- test if task is busy
Put_Line ("MAIN: NON-BLOCKING CALL SUCCEEDED -- TASK IS NOT BUSY");
else
Put_Line ("MAIN: NON-BLOCKING CALL FAILED -- TASK IS BUSY");
end select;
delay 1.0;
end loop;
Put_Line ("Main: Waiting for Reader (BLOCKING CALL)...");
Reader.Join;
Put_Line ("Main: all finished!");
end Main;
我为任务添加了另外两个条目:Join
和Ready
,它们的名称基本上相同。 Join提醒我对其进行阻塞调用,而Ready表示非阻塞调用适合测试任务可用性。之所以这样做,是因为有时我想知道Read()的上一次运行是否已完成而又没有触发新的运行。这使我可以整齐地执行此操作,并且完全没有任何离散标志!很棒。