Accept块内外语句的行为差异及ARM规范问询
Ada服务器任务实现分析与问题解答
服务器任务规格
task type Server_Task is entry E1(I: Integer); entry E2; entry E3; end Server_Task;
两种实现方案
实现1
task body Server_Task is begin loop select accept E1(I: Integer) do -- statements inside E1 using I -- statements inside E1 using I -- statements inside E1 using I null; end; or accept E2 do null; end; or accept E3 do null; end; end select; end loop; end Server_Task;
实现2
task body Server_Task is Temp: Integer; begin loop select accept E1(I: Integer) do Temp := I; end; -- statements outside E1 using Temp -- statements outside E1 using Temp -- statements outside E1 using Temp or accept E2 do null; end; or accept E3 do null; end; end select; end loop; end Server_Task;
客户端示例代码
ST: Server_Task; task body Client_Task is begin select ST.E2; else -- do something else null; end select; null; end Client_Task;
问题解答
1. 两种实现的行为差异是什么?
- 实现1中,E1的所有处理逻辑都在
accept块内执行:客户端调用E1时,会合会持续到accept块内所有语句执行完成,客户端会一直阻塞,直到服务器完成E1的全部处理后才能继续执行。 - 实现2中,
accept块仅完成参数传递(把I存入Temp),真正的业务逻辑在accept块外执行:会合在accept块结束时就完成,客户端会立即返回继续自己的流程,而服务器则在后台独立执行accept块外的逻辑,直到完成后才回到循环,等待新的入口调用。
2. 若E1的accept块外语句包含阻塞调用,导致服务器任务挂起,此时该任务与客户端的其他entry调用是否存在竞争?
不存在竞争。当服务器因E1的accept块外阻塞调用挂起时,它处于无法响应任何入口调用的状态。此时客户端调用E2、E3等入口时:
- 若为普通调用,会进入排队等待状态,直到服务器回到循环的
select语句后才能被处理; - 若为示例中带
else的选择调用,会直接执行else分支的逻辑,不会等待。
3. 上述行为是否在ARM(Ada Reference Manual)中有详细规定?
是的,ARM对相关行为有明确规定:
accept语句的会合过程从客户端发起入口调用开始,到accept块执行完毕时正式结束(ARM 9.5.3);- 任务在
accept块之外执行代码时,不属于会合阶段,此时任务不会响应任何新的入口调用,必须重新进入select或单独的accept语句后,才能再次接受客户端的入口请求(ARM 9.5)。
内容的提问来源于stack exchange,提问作者Sidisyom
相关产品推荐
相关产品推荐

