阻止时停止任务

时间:2012-08-20 10:01:04

标签: multitasking ada

让我先用代码说明这个问题:

with Ada.Text_IO;

procedure Test
is

   task type Serving_Task is
      entry Start;
   end Serving_Task;

   task body Serving_Task is begin
      accept Start;
      Ada.Text_IO.Put_Line ("Started");
      loop
         null; --  Blocking operation, eg. accepting on a socket.
         null; --  Processing on blocking operation's result.
      end loop;
      Ada.Text_IO.Put_Line ("Stopped");
   end Serving_Task;

   type Server is tagged limited record
      Serving : Serving_Task;
   end record;

   procedure Start
     (S : in out Server)
   is begin
      Ada.Text_IO.Put_Line ("Starting");
      S.Serving.Start;
   end Start;

   procedure Stop
     (S : in out Server)
   is begin
      Ada.Text_IO.Put_Line ("Stopping");
      -- TODO To implement.
   end Stop;

   Main_Server : Server;

begin
   Ada.Text_IO.Put_Line ("Calling Start");
   Start (Main_Server);
   delay 5.0;
   Ada.Text_IO.Put_Line ("Calling Stop");
   Stop (Main_Server);
end Test;

这是典型的服务器构造 - 有一个服务器任务,其中一个循环接受传入连接。我的问题是 - 为Stop类型实施Server程序的最佳方法是什么。

我希望它等到服务任务阻止接受套接字(或者就在阻塞调用之前,所以如果在终止任务之前完全处理每个接受的请求)并退出循环,那么任务可以清理在终止之前。

首先想到的是添加

select
   accept Stop;
or
   delay 0.1;
   exit;
end select;

在循环结束时,但每次迭代浪费了0.1秒。似乎很重要。

我已经看过RM,Lovelace教程和Wikibook中的一些例子,但似乎没有什么是合适的。

Ada中这种(相当常见的我相信)问题的最佳做法是什么?

答案是......

基于Marc Canswer https://gist.github.com/3413017

的解决方案示例

2 个答案:

答案 0 :(得分:2)

您需要else版本:

loop
   -- blocking read from socket
   -- process the data received
   select
      accept Stop;
      exit;
   else
      null;
   end select;
end loop;

答案 1 :(得分:2)

我通常设置它的方法首先是使用AdaCore的GNAT.Sockets包,而不是直接编程套接字。由于我将使用(套接字)select()函数(包装为Check_Selector)在套接字上有数据时通知,GNAT.Sockets提供了一个可以从其他地方调用的Abort_Selector()过程。在Check_Selector()上阻止任务时,我只是等待数据到达(状态=已完成)或标志它是时候退出(状态=已中止)。

请参阅TOMI_4_Ada包TCP_Connect中Monitor_Connections过程的开始(第397-416行)。从任务Connection_Monitoring(第469-495行)调用Monitor_Connections。