如何在Ada中实现非阻塞服务器?

Mir*_*nda 6 ada

我当前的设计看起来像这样

task body Agent_Task is
begin
    loop
        select
            accept Request_A do
            end Request_A;
        or
            accept Request_B do
            end Request_B;
        or
            ...
        else
            Do_Other_Stuff;
        end select;

    end loop;
exception
      when Exception_Id : others => Show_Exception (Exception_Id);
end Agent_Task;
Run Code Online (Sandbox Code Playgroud)

但是,当频繁调用代理中的条目(例如Request_A)时,它将变得无响应。有没有更好的结构让代理永远不会被阻塞?比如中断?

最耗时的部分在Do_Other_Stuff中,我希望服务器做的事情大致是:

loop
    Do_Other_Stuff;
    if interrupted, handle other requests.
end loop;
Run Code Online (Sandbox Code Playgroud)

这是一个学校协会,我无法修改测试程序来重试向代理发送的失败请求。当测试运行时,多个代理将同时相互通信。

Jef*_*ter 5

请注意,您的代码中有一个虚假end;代码,使其非法。

如果重要的是那些发出请求的人不会阻塞,您可以使用受保护的队列进行任务间通信:

loop
   select
      Request_Queue.Get (Item => Request);
      Process (Request => Request);
   else
      Do_Other_Stuff;
   end select;
end loop;
Run Code Online (Sandbox Code Playgroud)

请求在完成之前不会被处理Do_Other_Stuff,但是那些发出请求的人不会因为将请求放入队列而被阻止。

使用队列还允许您使用异步控制传输来为请求提供优先级Do_Other_Stuff

loop
   select
      Request_Queue.Get (Item => Request);
      Process (Request => Request);
   then abort
      Do_Other_Stuff;
   end select;
end loop;
Run Code Online (Sandbox Code Playgroud)

Do_Other_Stuff然后需要可中止,并且能够在下次运行时从中断处继续。Do_Other_Stuff但如果能像霍尔斯蒂建议的那样转移到另一项任务中那就更好了。

最后,如果您无法移动Do_Other_Stuff到另一个任务,并且无法中止它,您可能需要将其分成更短的部分:

loop
   Do_Some_Stuff;
   Handle_Requests;
   Do_Some_More_Stuff;
   Handle_Requests;
   ..
end loop;
Run Code Online (Sandbox Code Playgroud)

同样,使用队列更容易,因为accept语句不能进入子程序。


Nik*_*sti 4

将Do_Other_Stuff移至另一个任务,即将您的Agent_Task分成两个任务。

这有多困难取决于 Do_Other_Stuff 与 Request_A 和 Request_B 的操作之间有多少通信(数据流)。如果 Do_Other_Stuff 移至其自己的任务,则该任务必须通过集合点或受保护对象以某种方式与原始 Agent_Task 进行通信。如果 Do_Other_Stuff 是一个具有一些输入和一些输出的长计算,您可以向 Agent_Task 添加两个条目,一个用于向 Other_Stuff 任务提供输入,另一个用于接收来自 Other_Stuff 任务的输出。