我遇到了异步控制转移的不错的Ada功能,但不知何故,参考手册和示例应用程序并不适合。
以下示例写在Reference Manual 9.7.4:
中select
delay 5.0;
Put_Line("Calculation does not converge");
then abort
-- This calculation should finish in 5.0 seconds;
-- if not, it is assumed to diverge.
Horribly_Complicated_Recursive_Function(X, Y);
end select;
我现在以下列方式重建并运行它(完整文件):
with Ada.Text_IO; use Ada.Text_IO;
procedure asynch_transf_ex is
begin
Put_Line("Before Select");
select
delay 1.0;
-- will never be printed
Put_Line("1 Second is over");
then abort
loop
null;
end loop;
end select;
-- again, not printed
Put_Line("After Select");
end asynch_transf_ex;
(编译:gnatmake -gnat2012 -gnata -ggdb -O0 asynch_transf_ex.adb)
正如评论中所注意到的,循环永远运行并且不会中断。相比之下,参考手册指出,它应该在(大约)1秒后中断。
现在,有些情况下,中止地区的陈述可以安全地免于中止,如RM第9.8节所述:
但循环应该不是它们 - 实际上,如果我用null;
替换delay 0.0;
,那么执行将按预期运行。
在示例中提到了递归函数,我还想到函数调用在某种程度上是在时间结束后中止执行的触发器。但是,通过调用过程null;
替换procedure do_null is begin null; end;
并没有改变任何内容。 (我看了一下objdump - 电话没有被调整掉。)
阅读this explanation about GNAT's implementation of these constructs并没有帮助我。
那么,我是否会错过参考手册中的一点,或者这只是GNAT的一个问题?如果是这样,delay 0.0;
是否适合" Hotfix",还是有更好的解决方案?
感谢您的帮助。
我正在运行Linux(uname -r = 3.16.3-1-ARCH--来自Arch Linux-repos的标准内核,未修改),并且(如已提到信号,可能处理器类型很有趣,在英特尔(R)酷睿(TM)i5-4570 CPU @ 3.20GHz和英特尔奔腾987上尝试过它。
答案 0 :(得分:3)
虽然您引用的部分列出了可能不会发生中止的位置,即中止延迟操作,但如果不是,则不会立即发生中止 在中止延期的操作中。事实上,在9.8马币中,还有一个中止完成点列表:
除了这些直接的情况,执行构造 中止之前并不一定完成 abort_statement完成。但是,执行中止 构造完成不迟于其下一个中止完成点(如果 任何)在中止延期操作之外发生的;下列 是执行的中止完成点:
执行启动另一个任务的激活点;
任务激活结束;
执行条目调用,accept_statement,delay_statement或abort_statement的开始或结束;
执行select_statement或者exception_handler的sequence_of_statements的开始。
因此,如果一系列语句被中止,则在下一个语句发生之前不必发生中止。示例中的循环不会执行任何会导致中止完成点的循环;因此,仅使用9.8中的规则,中止永远不会发生。添加delay 0.0;
将提供中止完成点。
如果支持实时附件,则RM D.6(“抢先中止”)表示如果不是在中止延迟操作中,则必须立即在单处理器系统上发生中止。但是,附件D是可选的,并非所有实现都支持它。
如果您在Windows上运行,那么我认为不支持附件D,我认为不支持抢先中止,因为Windows没有提供一种安全的方法来立即终止线程而没有线程的合作。
GNAT支持在Windows上使用Polling
pragma;这会生成代码,检查另一个线程是否已尝试中止当前线程。