处理长 运行,阻塞函数
Handling long running, blocking functions
在一个项目中,我必须使用导入的 C 函数向服务器发送请求并接收响应。如果服务器不可访问,可以向此函数提供超时参数以指定阻塞函数之前的最长时间 returns。
不幸的是,这个超时并不总是可靠的,而且经常超过最大超时值。处理此类问题的最佳 Ada 方法是什么?
读完这篇chapter我不确定我是否可以使用这种编程模式?导入的 C 函数不是线程安全的,因此一次只能请求一个。一个完美的解决方案将允许发送一个请求(具有有效响应或超时响应通常由导入的 C 函数 return 编辑)并且可以使用第二个函数来查询最后一个请求是否超时。在导入的 C 函数调用 returned 之前,进一步的请求应始终 return 超时响应。
我不确定如果选择延迟选项,条目(条目内的编程语句)Password_Server.Set
和 Process_Data.Output
会发生什么情况?
如果入口调用排队或等待访问受保护对象 (PO),则入口调用在延迟期满时中止,执行延迟分支,select 完成。如果在延迟到期时入口调用已被接受(任务)或正在执行(PO),它将继续直到完成或重新排队。如果完成,则执行入口分支并完成 select。如果它被中止重新排队,它的行为就像它最初那样。如果在没有中止的情况下重新排队,则延迟分支将被忽略。 (注意如果是requeued without abort,后面还是可以requeued with abort,所以事情会比较复杂,这样的设计最好尽量避免。)
IIUC 正确,您一次只希望一个任务能够调用 C 操作。如果一个任务正在调用它而另一个任务试图调用它,则第二个任务应该被告知调用超时。如果 C 操作花费的时间超过其超时时间,Ada 应该中止它。
我能看到中止对 C 的调用的唯一方法是使用异步控制转移。这是否真的会做我们想要的是一个悬而未决的问题。
这让我想到了
package Calling_C is
type Data is ...
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Calling_C;
package body Calling_C is
task Control is
entry Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Control;
task body Control is
begin
Forever : loop
select
accept Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) do
select
delay Timeout;
Timed_Out := True;
then abort
-- Call the C operation
end select;
end Call_C;
or
terminate;
end select;
end loop Forever;
end Control;
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) is
begin
select
Control.Call_C (Info => Info, Timeout => Timeout, Timed_Out => Timed_Out);
else
Timed_Out := True;
end Select;
end Call_C;
end Calling_C;
第一个任务进入并调用C操作。不会立即接受后续任务,并且 return 和 Timed_Out 设置为 True。如果对 C 的调用没有及时 return,可能它已中止。
我其实还不太了解 Ada。在这里发布我的想法,以便专业人士可以告诉我这是否是一个坏主意。服务器看起来像这样:
task Server is
entry Request (in Input : Input_Type);
entry Response (out Output : Output_Type);
end Server;
task body Server is
Local_Input : Input_Type;
Local_Output : Output_Type;
begin
accept Request (Input : in Input_Type) do
Local_Input := Input;
end Request;
Local_Output := My_C_Code(Local_Input);
accept Response(Output : out Output_Type) do
Output := Local_Output;
end Response;
end Server;
使用方法:
Server.Request(Input);
select
Server.Response(Output);
-- got your response
or
delay Timeout;
-- response timeout
end select;
您可能已经意识到服务器将阻塞响应,直到请求调用者(或其他任何人)决定调用它。我最好的猜测是 a) 添加 select ... or terminate
,或 b) 处理超时并返回等待响应、同步或异步。
在一个项目中,我必须使用导入的 C 函数向服务器发送请求并接收响应。如果服务器不可访问,可以向此函数提供超时参数以指定阻塞函数之前的最长时间 returns。
不幸的是,这个超时并不总是可靠的,而且经常超过最大超时值。处理此类问题的最佳 Ada 方法是什么?
读完这篇chapter我不确定我是否可以使用这种编程模式?导入的 C 函数不是线程安全的,因此一次只能请求一个。一个完美的解决方案将允许发送一个请求(具有有效响应或超时响应通常由导入的 C 函数 return 编辑)并且可以使用第二个函数来查询最后一个请求是否超时。在导入的 C 函数调用 returned 之前,进一步的请求应始终 return 超时响应。
我不确定如果选择延迟选项,条目(条目内的编程语句)Password_Server.Set
和 Process_Data.Output
会发生什么情况?
如果入口调用排队或等待访问受保护对象 (PO),则入口调用在延迟期满时中止,执行延迟分支,select 完成。如果在延迟到期时入口调用已被接受(任务)或正在执行(PO),它将继续直到完成或重新排队。如果完成,则执行入口分支并完成 select。如果它被中止重新排队,它的行为就像它最初那样。如果在没有中止的情况下重新排队,则延迟分支将被忽略。 (注意如果是requeued without abort,后面还是可以requeued with abort,所以事情会比较复杂,这样的设计最好尽量避免。)
IIUC 正确,您一次只希望一个任务能够调用 C 操作。如果一个任务正在调用它而另一个任务试图调用它,则第二个任务应该被告知调用超时。如果 C 操作花费的时间超过其超时时间,Ada 应该中止它。
我能看到中止对 C 的调用的唯一方法是使用异步控制转移。这是否真的会做我们想要的是一个悬而未决的问题。
这让我想到了
package Calling_C is
type Data is ...
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Calling_C;
package body Calling_C is
task Control is
entry Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Control;
task body Control is
begin
Forever : loop
select
accept Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) do
select
delay Timeout;
Timed_Out := True;
then abort
-- Call the C operation
end select;
end Call_C;
or
terminate;
end select;
end loop Forever;
end Control;
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) is
begin
select
Control.Call_C (Info => Info, Timeout => Timeout, Timed_Out => Timed_Out);
else
Timed_Out := True;
end Select;
end Call_C;
end Calling_C;
第一个任务进入并调用C操作。不会立即接受后续任务,并且 return 和 Timed_Out 设置为 True。如果对 C 的调用没有及时 return,可能它已中止。
我其实还不太了解 Ada。在这里发布我的想法,以便专业人士可以告诉我这是否是一个坏主意。服务器看起来像这样:
task Server is
entry Request (in Input : Input_Type);
entry Response (out Output : Output_Type);
end Server;
task body Server is
Local_Input : Input_Type;
Local_Output : Output_Type;
begin
accept Request (Input : in Input_Type) do
Local_Input := Input;
end Request;
Local_Output := My_C_Code(Local_Input);
accept Response(Output : out Output_Type) do
Output := Local_Output;
end Response;
end Server;
使用方法:
Server.Request(Input);
select
Server.Response(Output);
-- got your response
or
delay Timeout;
-- response timeout
end select;
您可能已经意识到服务器将阻塞响应,直到请求调用者(或其他任何人)决定调用它。我最好的猜测是 a) 添加 select ... or terminate
,或 b) 处理超时并返回等待响应、同步或异步。