任务:响应非常慢
Tasking: Very slow response
我的实际程序创建了一个任务,但我没有按应有的方式对控制消息做出反应。由于它已经变得相当大,我提供了一个具有相同控制逻辑的简短测试程序。它创建一个后台任务,每 0.1 秒重复一个循环。根据受保护的标志“运行”,它会打印出 'a',或者什么都不做。当我设置“运行”时,程序立即关闭,打印 'a's。但是当我设置“stopreq”时,它需要几秒钟,有时甚至超过 10 秒,直到它停止。我希望响应时间为 0.1 或 0.2 秒。
有人有解释和解决办法吗?
我的主程序打开一个带有 3 个按钮的 window:“开始”调用下面的子程序“开始”,“停止”调用 Request_Stop,“退出”调用 Request_Quit.我正在使用 PC 运行 Linux.
这是我的任务包的主体。如果您需要更多,请告诉我,我 post 其他部分。
with Ada.Text_IO;
with Ada.Calendar;
package body Tasking is
t_step: constant Duration:= 0.1;
dti: Duration;
protected Sync is
procedure Start; -- sim. shall start
procedure Request_Stop; -- sim. shall stop
procedure Stop_If_Req;
function Is_Running return Boolean; -- sim. is running
procedure Request_Quit; -- sim.task shall exit
function Quit_Requested return Boolean; -- quit has been requested
procedure Reset_Time;
procedure Increment_Time (dt: Duration);
procedure Delay_Until;
private
running: Boolean:= false;
stopreq: Boolean:= false;
quitreq: Boolean:= false;
ti: Ada.Calendar.Time;
end Sync;
protected body Sync is
procedure Start is begin running:= true; end Start;
procedure Request_Stop is
begin
if running then stopreq:= true; end if;
end Request_Stop;
procedure Stop_If_Req is
begin
if stopreq then
running:= false;
stopreq:= false;
end if;
end Stop_If_Req;
function Is_Running return Boolean is begin return running; end Is_Running;
procedure Request_Quit is begin quitreq:= true; end Request_Quit;
function Quit_Requested return Boolean
is begin return quitreq; end Quit_Requested;
procedure Reset_Time is begin ti:= Ada.Calendar.Clock; end Reset_Time;
procedure Increment_Time (dt: Duration) is
begin
ti:= Ada.Calendar."+"(ti, dt);
dti:= dt;
end Increment_Time;
procedure Delay_Until is
use type Ada.Calendar.Time;
now: Ada.Calendar.Time;
begin
now:= Ada.Calendar.Clock;
while ti < now loop -- while time over
ti:= ti + dti;
end loop;
delay until ti;
end Delay_Until;
end Sync;
task body Thread is
begin
Ada.Text_IO.Put_Line("starting task");
while not Sync.Quit_Requested loop
if sync.Is_Running then
sync.Increment_Time (t_step);
sync.Delay_Until;
Ada.Text_IO.Put("a");
sync.Stop_If_Req;
else
delay t_step;
sync.Reset_Time;
end if;
end loop;
end Thread;
procedure Start is
begin
Sync.Start;
end Start;
function Is_Running return Boolean is
begin
return Sync.Is_Running;
end Is_Running;
procedure Request_Stop is
begin
Ada.Text_IO.Put_Line("");
Sync.Request_Stop;
end Request_Stop;
procedure Request_Quit is
begin
Sync.Request_Quit;
end Request_Quit;
end Tasking;
你的代码描述和注释太差,我无法理解你想要它做什么。
但是在受保护的操作 (Sync.Delay_Until) 中使用“delay until”语句是不正确的——这是一个“有界错误”。如果有效,它可能会阻止对该受保护对象的所有其他调用,直到延迟期满。我建议您在尝试更正代码时应该从那里开始。
感谢您的评论,该程序现在可以正常运行。
致 Jesper Quorning:
“过去的时间”在这里不是问题,但在我的实际软件项目中可能是这样。尽管如此,我还是在下面的更正版本中包含了一个补救措施,因此它可以作为其他人的模式。谢谢提示。
致尼克拉斯·霍尔斯蒂:
我将“delay until”从受保护的操作中移出,程序现在按预期运行,感谢您的解释。 (有时一个运行不好的程序比一个根本不运行的程序更糟糕,因为在后一种情况下你更认真地对待编译器警告。)
我想做的是:
- 以精确定义的时间间隔执行应用程序
- 能够enable/disable随时
- 仅在明确定义的状态下才给它时间停止
- 知道了,什么时候真的停止了
- 整个事情的受控终止。
我的实现思路是:
- 将应用程序作为单独的任务无限循环调用
- 检查循环顶部是否请求退出
- 如果启用则执行应用程序的 if 语句
- 否则简单延迟。
来自其他包的控制是通过 public 子程序完成的
开始,Is_Running、Request_Stop、Request_Quit。
除了上面提到的更正之外,我重新命名了一些项目以使其作用更加明确。
如果有标准解,和我的不一样,我想看看
这是我更正的程序:
with Ada.Text_IO;
with Ada.Calendar;
package body Tasking is
t_step: constant Duration:= 0.1;
protected Sync is
procedure Enable_App; -- enable application
procedure Request_Disable; -- request disabling of app.
procedure Disable_If_Req; -- disable app. if requested
function Enabled return Boolean; -- application is enabled
procedure Request_Quit; -- task shall terminate
function Quit_Requested return Boolean; -- task termination requested
procedure Set_Time (t: Ada.Calendar.Time); -- set execution time
function Get_Time return Ada.Calendar.Time; -- get execution time
private
running: Boolean:= false; -- application is enabled
stopreq: Boolean:= false; -- disabling has been requested
quitreq: Boolean:= false; -- task termination requested
ti: Ada.Calendar.Time; -- time of next app. execution
end Sync;
protected body Sync is
procedure Enable_App is begin running:= true; end Enable_App;
procedure Request_Disable is
begin
if running then stopreq:= true; end if;
end Request_Disable;
procedure Disable_If_Req is
begin
if stopreq then
running:= false;
stopreq:= false;
end if;
end Disable_If_Req;
function Enabled return Boolean is
begin return running; end Enabled;
procedure Request_Quit is
begin quitreq:= true; end Request_Quit;
function Quit_Requested return Boolean
is begin return quitreq; end Quit_Requested;
procedure Set_Time (t: Ada.Calendar.Time) is
begin ti:= t; end Set_Time;
function Get_Time return Ada.Calendar.Time is
begin return ti; end Get_Time;
end Sync;
task body Thread is
use type Ada.Calendar.Time;
now: Ada.Calendar.Time;
begin
Ada.Text_IO.Put_Line("starting task");
while not Sync.Quit_Requested loop
if sync.Enabled then
-- increment time if it is too late
now:= Ada.Calendar.Clock;
while sync.Get_Time <= now loop
sync.Set_Time (sync.Get_Time + t_step);
end loop;
-- wait until next execution time
delay until sync.Get_Time;
-- execute application and set time for next execution
Ada.Text_IO.Put(".");
sync.Set_Time (sync.Get_Time + t_step);
-- disable application if this has been requested
sync.Disable_If_Req;
else
-- wait for enabling and set time for next execution
delay t_step;
sync.Set_Time (Ada.Calendar.Clock + t_Step);
end if;
end loop;
end Thread;
procedure Start is
begin
Sync.Enable_App;
end Start;
function Is_Running return Boolean is
begin
return Sync.Enabled;
end Is_Running;
procedure Request_Stop is
begin
Ada.Text_IO.Put_Line("");
Sync.Request_Disable;
end Request_Stop;
procedure Request_Quit is
begin
Sync.Request_Quit;
end Request_Quit;
end Tasking;
关于 Ada 任务的一些一般想法:
- 从概念上讲,Ada 任务有自己的处理器,没有其他任务在其上运行。调度,例如确定任务下一步应该做什么,通常是任务的责任。
- 当任务必须等待一个事件时,任务通常最好是阻塞而不是轮询。
- Ada.Calendar 通常是当地时间,甚至可以倒退。如果可能,任务应使用 Ada.Real_Time 自行安排。
所以我会做类似的事情
protected Control is
procedure Set_Running (Running : in Boolean := True);
-- Set whether the task should run or not
-- Initially Running is False
entry Wait_Until_Running;
-- Blocks the caller until Running is set to True
function Running return Boolean;
-- Returns the current value of Running
procedure Quit_Now;
-- Tell the task to quit
function Quitting return Boolean;
-- Returns True when Quit_Now has been called; False otherwise
private -- Control
Run : Boolean := False;
Quit : Boolean := False;
end Control;
task body T is
Step : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Milliseconds (100);
Next : Ada.Real_Time.Time;
begin -- T
Forever : loop
Control.Wait_Until_Running;
Next := Ada.Real_Time.Clock;
Run : while Control.Running loop
exit Forever when Control.Quitting;
delay until Next;
Next := Next + Step;
-- The task does its thing here
Ada.Text_IO.Put (Item => 'a');
end loop Run;
end loop Forever;
end T;
protected body Control is
procedure Set_Running (Running : in Boolean := True) is
begin
Run := Running;
end Set_Running;
entry Wait_Until_Running when Run is
begin
null;
end Wait_Until_Running;
function Running return Boolean is (Run);
procedure Quit_Now is
begin
Run := True; -- Release the task if it is blocked on Wait_Until_Running
Quit := True;
end Quit_Now;
function Quitting return Boolean is (Quit);
end Control;
感谢您对目标的新描述,@hreba,很高兴听到您的程序现在按预期工作。
我同意@Anh Vo 的观点,应用程序任务可以通过任务条目来控制,但我认为使用受保护对象 (PO) 更可取,因为它将调用者(主任务)与应用程序任务分离-- 它不会让调用者等到应用程序任务准备好接受入口调用。但是,我会减少 PO 来处理 inter-task 通信。在@hreba 代码中,我认为没有理由使用受保护的操作 Set_Time 和 Get_Time,因为时间似乎完全由应用程序任务控制。
下面是我的编程方式。首先,我会为应用程序任务的状态定义一个枚举,而不是一些布尔值:
type App_State is (Enabled, Disabled, Stopping, Stopped);
在@hreba 代码中,应用程序任务似乎最初“不是运行”,所以
Initial_State : constant App_State := Disabled;
然后 PO 将声明为(我省略了评论,因为我将以散文形式评论):
protected App_Control is
procedure Enable;
procedure Disable;
procedure Stop;
entry Get_New_State (New_State : out App_State);
entry Wait_Until_Stopped;
private
State : App_State := Initial_State;
Old_State : App_State := Initial_State;
end App_Control;
PO 操作启用、禁用和停止做显而易见的事情:
procedure Enable
is
begin
State := Enabled;
end Enable;
禁用和停止类似。停止将状态设置为正在停止。
条目Get_New_State将在应用程序任务中调用以接收新状态。它是一个条目,而不是函数或过程,因此只有在状态发生变化时才能调用它:
entry Get_New_State (New_State : out App_State)
when State /= Old_State
is
begin
New_State := State;
Old_State := State;
if State = Stopping then
State := Stopped;
end if;
end Get_New_State;
在这里,一旦应用程序任务被赋予,我就自动从 Stopping 过渡到 Stopped New_State = Stopping。如果应用程序任务在被认为真正停止之前必须执行一些 clean-up,则应将该转换移动到单独的操作,例如过程 App_Control.Has_Stopped,然后从应用程序任务调用 clean-up.
条目Wait_Until_Stopped可以在主任务中调用,等待应用任务停止。很简单:
entry Wait_Until_Stopped
when State = Stopped
is
begin
null;
end Wait_Until_Stopped;
现在是申请任务。我的设计与原来的设计有一个主要区别:为了使任务对“停止”命令的响应更快,我使用 Get_New_State 的定时进入调用让该调用在应用程序任务等待下一个时发生激活时间。如果任务是每 0.1 秒 运行,这可能无关紧要,但在某些其他情况下,任务可能是每 10 秒或每 10 分钟 运行,然后它可能很重要。所以这是任务正文:
task body App_Thread
is
use Ada.Calendar;
Period : constant Duration := 0.1;
State : App_State := Initial_State;
Next_Time : Time := Clock + Period;
begin
loop
select
App_Control.Get_New_State (New_State => State);
exit when State = Stopping;
or
delay until Next_Time;
if State = Enabled then
Execute_The_Application;
end if;
Next_Time := Next_Time + Period;
end select;
end loop;
end App_Thread;
要解耦调用任务和被调用任务,不要使用accept {entry name} do 语句。只需将其分成两个单独的语句,如下所示,条目 Start_Work 例如
--耦合案例
接受 Start_Work 做
Execute_The_Application
结束 Start_Work;
--解耦案例
接受 Start_Work;
Execute_The_Application;
这是我对@hreba 要求的实现。
包任务是
-- 更多代码
task Thread2 is
entry Start_Work;
entry Stop_Work;
entry Quitting_Time;
end Thread2;
task body Thread2 is
use type Ada.Real_Time.Time;
T_Step : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Milliseconds (100);
Next_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock;
begin
Ada.Text_IO.Put_Line("task Thread2 elaborates and activates");
Forever: loop
select
accept Quitting_Time;
Ada.Text_IO.Put_Line ("task Thread2 terminates. Later alligator");
exit Forever; -- later alligator
or
accept Start_Work;
Working: loop
Ada.Text_IO.Put_Line ("Ada");
Next_Time := Next_Time + T_Step;
select
accept Stop_Work;
exit Working;
or
delay until Next_Time;
end select;
end loop Working;
or
Terminate;
end select;
end loop Forever;
end Thread2;
-- 更多代码
结束任务;
我的实际程序创建了一个任务,但我没有按应有的方式对控制消息做出反应。由于它已经变得相当大,我提供了一个具有相同控制逻辑的简短测试程序。它创建一个后台任务,每 0.1 秒重复一个循环。根据受保护的标志“运行”,它会打印出 'a',或者什么都不做。当我设置“运行”时,程序立即关闭,打印 'a's。但是当我设置“stopreq”时,它需要几秒钟,有时甚至超过 10 秒,直到它停止。我希望响应时间为 0.1 或 0.2 秒。
有人有解释和解决办法吗?
我的主程序打开一个带有 3 个按钮的 window:“开始”调用下面的子程序“开始”,“停止”调用 Request_Stop,“退出”调用 Request_Quit.我正在使用 PC 运行 Linux.
这是我的任务包的主体。如果您需要更多,请告诉我,我 post 其他部分。
with Ada.Text_IO;
with Ada.Calendar;
package body Tasking is
t_step: constant Duration:= 0.1;
dti: Duration;
protected Sync is
procedure Start; -- sim. shall start
procedure Request_Stop; -- sim. shall stop
procedure Stop_If_Req;
function Is_Running return Boolean; -- sim. is running
procedure Request_Quit; -- sim.task shall exit
function Quit_Requested return Boolean; -- quit has been requested
procedure Reset_Time;
procedure Increment_Time (dt: Duration);
procedure Delay_Until;
private
running: Boolean:= false;
stopreq: Boolean:= false;
quitreq: Boolean:= false;
ti: Ada.Calendar.Time;
end Sync;
protected body Sync is
procedure Start is begin running:= true; end Start;
procedure Request_Stop is
begin
if running then stopreq:= true; end if;
end Request_Stop;
procedure Stop_If_Req is
begin
if stopreq then
running:= false;
stopreq:= false;
end if;
end Stop_If_Req;
function Is_Running return Boolean is begin return running; end Is_Running;
procedure Request_Quit is begin quitreq:= true; end Request_Quit;
function Quit_Requested return Boolean
is begin return quitreq; end Quit_Requested;
procedure Reset_Time is begin ti:= Ada.Calendar.Clock; end Reset_Time;
procedure Increment_Time (dt: Duration) is
begin
ti:= Ada.Calendar."+"(ti, dt);
dti:= dt;
end Increment_Time;
procedure Delay_Until is
use type Ada.Calendar.Time;
now: Ada.Calendar.Time;
begin
now:= Ada.Calendar.Clock;
while ti < now loop -- while time over
ti:= ti + dti;
end loop;
delay until ti;
end Delay_Until;
end Sync;
task body Thread is
begin
Ada.Text_IO.Put_Line("starting task");
while not Sync.Quit_Requested loop
if sync.Is_Running then
sync.Increment_Time (t_step);
sync.Delay_Until;
Ada.Text_IO.Put("a");
sync.Stop_If_Req;
else
delay t_step;
sync.Reset_Time;
end if;
end loop;
end Thread;
procedure Start is
begin
Sync.Start;
end Start;
function Is_Running return Boolean is
begin
return Sync.Is_Running;
end Is_Running;
procedure Request_Stop is
begin
Ada.Text_IO.Put_Line("");
Sync.Request_Stop;
end Request_Stop;
procedure Request_Quit is
begin
Sync.Request_Quit;
end Request_Quit;
end Tasking;
你的代码描述和注释太差,我无法理解你想要它做什么。
但是在受保护的操作 (Sync.Delay_Until) 中使用“delay until”语句是不正确的——这是一个“有界错误”。如果有效,它可能会阻止对该受保护对象的所有其他调用,直到延迟期满。我建议您在尝试更正代码时应该从那里开始。
感谢您的评论,该程序现在可以正常运行。
致 Jesper Quorning:
“过去的时间”在这里不是问题,但在我的实际软件项目中可能是这样。尽管如此,我还是在下面的更正版本中包含了一个补救措施,因此它可以作为其他人的模式。谢谢提示。
致尼克拉斯·霍尔斯蒂:
我将“delay until”从受保护的操作中移出,程序现在按预期运行,感谢您的解释。 (有时一个运行不好的程序比一个根本不运行的程序更糟糕,因为在后一种情况下你更认真地对待编译器警告。)
我想做的是:
- 以精确定义的时间间隔执行应用程序
- 能够enable/disable随时
- 仅在明确定义的状态下才给它时间停止
- 知道了,什么时候真的停止了
- 整个事情的受控终止。
我的实现思路是:
- 将应用程序作为单独的任务无限循环调用
- 检查循环顶部是否请求退出
- 如果启用则执行应用程序的 if 语句
- 否则简单延迟。 来自其他包的控制是通过 public 子程序完成的 开始,Is_Running、Request_Stop、Request_Quit。 除了上面提到的更正之外,我重新命名了一些项目以使其作用更加明确。
如果有标准解,和我的不一样,我想看看
这是我更正的程序:
with Ada.Text_IO;
with Ada.Calendar;
package body Tasking is
t_step: constant Duration:= 0.1;
protected Sync is
procedure Enable_App; -- enable application
procedure Request_Disable; -- request disabling of app.
procedure Disable_If_Req; -- disable app. if requested
function Enabled return Boolean; -- application is enabled
procedure Request_Quit; -- task shall terminate
function Quit_Requested return Boolean; -- task termination requested
procedure Set_Time (t: Ada.Calendar.Time); -- set execution time
function Get_Time return Ada.Calendar.Time; -- get execution time
private
running: Boolean:= false; -- application is enabled
stopreq: Boolean:= false; -- disabling has been requested
quitreq: Boolean:= false; -- task termination requested
ti: Ada.Calendar.Time; -- time of next app. execution
end Sync;
protected body Sync is
procedure Enable_App is begin running:= true; end Enable_App;
procedure Request_Disable is
begin
if running then stopreq:= true; end if;
end Request_Disable;
procedure Disable_If_Req is
begin
if stopreq then
running:= false;
stopreq:= false;
end if;
end Disable_If_Req;
function Enabled return Boolean is
begin return running; end Enabled;
procedure Request_Quit is
begin quitreq:= true; end Request_Quit;
function Quit_Requested return Boolean
is begin return quitreq; end Quit_Requested;
procedure Set_Time (t: Ada.Calendar.Time) is
begin ti:= t; end Set_Time;
function Get_Time return Ada.Calendar.Time is
begin return ti; end Get_Time;
end Sync;
task body Thread is
use type Ada.Calendar.Time;
now: Ada.Calendar.Time;
begin
Ada.Text_IO.Put_Line("starting task");
while not Sync.Quit_Requested loop
if sync.Enabled then
-- increment time if it is too late
now:= Ada.Calendar.Clock;
while sync.Get_Time <= now loop
sync.Set_Time (sync.Get_Time + t_step);
end loop;
-- wait until next execution time
delay until sync.Get_Time;
-- execute application and set time for next execution
Ada.Text_IO.Put(".");
sync.Set_Time (sync.Get_Time + t_step);
-- disable application if this has been requested
sync.Disable_If_Req;
else
-- wait for enabling and set time for next execution
delay t_step;
sync.Set_Time (Ada.Calendar.Clock + t_Step);
end if;
end loop;
end Thread;
procedure Start is
begin
Sync.Enable_App;
end Start;
function Is_Running return Boolean is
begin
return Sync.Enabled;
end Is_Running;
procedure Request_Stop is
begin
Ada.Text_IO.Put_Line("");
Sync.Request_Disable;
end Request_Stop;
procedure Request_Quit is
begin
Sync.Request_Quit;
end Request_Quit;
end Tasking;
关于 Ada 任务的一些一般想法:
- 从概念上讲,Ada 任务有自己的处理器,没有其他任务在其上运行。调度,例如确定任务下一步应该做什么,通常是任务的责任。
- 当任务必须等待一个事件时,任务通常最好是阻塞而不是轮询。
- Ada.Calendar 通常是当地时间,甚至可以倒退。如果可能,任务应使用 Ada.Real_Time 自行安排。
所以我会做类似的事情
protected Control is
procedure Set_Running (Running : in Boolean := True);
-- Set whether the task should run or not
-- Initially Running is False
entry Wait_Until_Running;
-- Blocks the caller until Running is set to True
function Running return Boolean;
-- Returns the current value of Running
procedure Quit_Now;
-- Tell the task to quit
function Quitting return Boolean;
-- Returns True when Quit_Now has been called; False otherwise
private -- Control
Run : Boolean := False;
Quit : Boolean := False;
end Control;
task body T is
Step : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Milliseconds (100);
Next : Ada.Real_Time.Time;
begin -- T
Forever : loop
Control.Wait_Until_Running;
Next := Ada.Real_Time.Clock;
Run : while Control.Running loop
exit Forever when Control.Quitting;
delay until Next;
Next := Next + Step;
-- The task does its thing here
Ada.Text_IO.Put (Item => 'a');
end loop Run;
end loop Forever;
end T;
protected body Control is
procedure Set_Running (Running : in Boolean := True) is
begin
Run := Running;
end Set_Running;
entry Wait_Until_Running when Run is
begin
null;
end Wait_Until_Running;
function Running return Boolean is (Run);
procedure Quit_Now is
begin
Run := True; -- Release the task if it is blocked on Wait_Until_Running
Quit := True;
end Quit_Now;
function Quitting return Boolean is (Quit);
end Control;
感谢您对目标的新描述,@hreba,很高兴听到您的程序现在按预期工作。
我同意@Anh Vo 的观点,应用程序任务可以通过任务条目来控制,但我认为使用受保护对象 (PO) 更可取,因为它将调用者(主任务)与应用程序任务分离-- 它不会让调用者等到应用程序任务准备好接受入口调用。但是,我会减少 PO 来处理 inter-task 通信。在@hreba 代码中,我认为没有理由使用受保护的操作 Set_Time 和 Get_Time,因为时间似乎完全由应用程序任务控制。
下面是我的编程方式。首先,我会为应用程序任务的状态定义一个枚举,而不是一些布尔值:
type App_State is (Enabled, Disabled, Stopping, Stopped);
在@hreba 代码中,应用程序任务似乎最初“不是运行”,所以
Initial_State : constant App_State := Disabled;
然后 PO 将声明为(我省略了评论,因为我将以散文形式评论):
protected App_Control is
procedure Enable;
procedure Disable;
procedure Stop;
entry Get_New_State (New_State : out App_State);
entry Wait_Until_Stopped;
private
State : App_State := Initial_State;
Old_State : App_State := Initial_State;
end App_Control;
PO 操作启用、禁用和停止做显而易见的事情:
procedure Enable
is
begin
State := Enabled;
end Enable;
禁用和停止类似。停止将状态设置为正在停止。
条目Get_New_State将在应用程序任务中调用以接收新状态。它是一个条目,而不是函数或过程,因此只有在状态发生变化时才能调用它:
entry Get_New_State (New_State : out App_State)
when State /= Old_State
is
begin
New_State := State;
Old_State := State;
if State = Stopping then
State := Stopped;
end if;
end Get_New_State;
在这里,一旦应用程序任务被赋予,我就自动从 Stopping 过渡到 Stopped New_State = Stopping。如果应用程序任务在被认为真正停止之前必须执行一些 clean-up,则应将该转换移动到单独的操作,例如过程 App_Control.Has_Stopped,然后从应用程序任务调用 clean-up.
条目Wait_Until_Stopped可以在主任务中调用,等待应用任务停止。很简单:
entry Wait_Until_Stopped
when State = Stopped
is
begin
null;
end Wait_Until_Stopped;
现在是申请任务。我的设计与原来的设计有一个主要区别:为了使任务对“停止”命令的响应更快,我使用 Get_New_State 的定时进入调用让该调用在应用程序任务等待下一个时发生激活时间。如果任务是每 0.1 秒 运行,这可能无关紧要,但在某些其他情况下,任务可能是每 10 秒或每 10 分钟 运行,然后它可能很重要。所以这是任务正文:
task body App_Thread
is
use Ada.Calendar;
Period : constant Duration := 0.1;
State : App_State := Initial_State;
Next_Time : Time := Clock + Period;
begin
loop
select
App_Control.Get_New_State (New_State => State);
exit when State = Stopping;
or
delay until Next_Time;
if State = Enabled then
Execute_The_Application;
end if;
Next_Time := Next_Time + Period;
end select;
end loop;
end App_Thread;
要解耦调用任务和被调用任务,不要使用accept {entry name} do 语句。只需将其分成两个单独的语句,如下所示,条目 Start_Work 例如
--耦合案例 接受 Start_Work 做 Execute_The_Application 结束 Start_Work;
--解耦案例 接受 Start_Work; Execute_The_Application;
这是我对@hreba 要求的实现。
包任务是 -- 更多代码
task Thread2 is
entry Start_Work;
entry Stop_Work;
entry Quitting_Time;
end Thread2;
task body Thread2 is
use type Ada.Real_Time.Time;
T_Step : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Milliseconds (100);
Next_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock;
begin
Ada.Text_IO.Put_Line("task Thread2 elaborates and activates");
Forever: loop
select
accept Quitting_Time;
Ada.Text_IO.Put_Line ("task Thread2 terminates. Later alligator");
exit Forever; -- later alligator
or
accept Start_Work;
Working: loop
Ada.Text_IO.Put_Line ("Ada");
Next_Time := Next_Time + T_Step;
select
accept Stop_Work;
exit Working;
or
delay until Next_Time;
end select;
end loop Working;
or
Terminate;
end select;
end loop Forever;
end Thread2;
-- 更多代码 结束任务;