Ada编程中的CORSO应用与天花板协议问题解析
1. Ada CORSO绑定与生产者/消费者示例
1.1 LSYS中的进程注册
在实现CORSO应用时,需要在LSYS中注册进程。通过
CoKe.Entries
包可以完成这一操作,所有CORSO进程实际上都是
Proc_Ptr
形式的Ada过程。下面是
CoKe.Entries
包的代码:
with CoKe.Base.Attribute;
package CoKe.Entries is
type Proc_Ptr is access
procedure(Param: CoKe.Base.Attribute.CoKeBaseAttribute’CLASS);
type CoKeBaseAttribute_AD is
access all CoKe.Base.Attribute.CoKeBaseAttribute’CLASS;
procedure Add_CoKe_Entry(
Name: string;
Run: Proc_Ptr);
procedure Start_CoKe_Entry(
Name: string;
Param: CoKeBaseAttribute_AD);
end CoKe.Entries;
参数
Param
可使用IDL类型
CoKeStruct
传递任意复杂的数据结构。
1.2 生产者/消费者示例
1.2.1 相关包定义
在生产者/消费者示例中,使用了以下包:
-- 包 My_SharedCoKeInt
with Coke, My_CoKeInt, Shared;
package My_SharedCoKeInt is new Shared(My_CoKeInt.CokeInt,CoKe.stream);
-- 包 My_TxedSharedCoKeInt
with My_SharedCoKeInt, Tx;
package My_TxedSharedCoKeInt is new Tx(My_SharedCoKeInt);
1.2.2 生产者和消费者过程
通过调用
CoKe.Entries.Add_CoKe_Entry
将
Producer
和
Consumer
过程注册为CORSO进程。在注册之前,需要调用
LSYSConnect
建立与LSYS的连接,然后使用
CreateIndependentProcess
执行这些过程,并传递相同的OID以标识用于通信的共享对象流。
以下是
Producer
过程的代码:
with CoKe.Base.Attribute.CoKeOid, CoKe.Base.Streams, My_SharedCoKeInt,
My_TxedSharedCoKeInt, Transaction_Mgt;
use CoKe.Base.Attribute.CoKeOid, CoKe.Base.Streams, My_SharedCoKeInt,
My_TxedSharedCoKeInt, Transaction_Mgt;
procedure Producer(Param: CoKe.Base.Attribute.CoKeBaseAttribute’CLASS)
is
data: My_TxedSharedCoKeInt.Txed;
CoKe_Strm: aliased CoKe_Stream;
Oid: CoKeOid := CoKeOid(Param);
begin
Set_Oid(Shared(data), Oid);
-- attach Oid we have got from Param to data
for i in 1..3 loop
Int_to_CoKeInt(from => i, to => data);
declare
topTx: Tx := Create_TX;
-- create and open a transaction
begin
Set_Tx(data,topTx);
-- attach transaction to data
loop
Txed’WRITE(CoKe_Strm’access, data);
-- write data to VSM
exit when Commit(topTx);
-- exit if everything is okay
Cancel(topTx);
-- cancel transaction if something went wrong
end loop;
end;
end loop;
Process_Commit;
-- exit in commit state
end Producer;
以下是
Consumer
过程的代码:
with CoKe.Base.Attribute.CoKeOid, CoKe.Base.Streams, My_SharedCoKeInt,
Text_IO;
use CoKe.Base.Attribute.CoKeOid, CoKe.Base.Streams, My_SharedCoKeInt;
procedure Consumer(Param: CoKe.Base.Attribute.CoKeBaseAttribute’CLASS)
is
data: shared;
CoKe_Strm: aliased CoKe_Stream;
Oid: CoKeOid := CoKeOid(Param);
begin
Set_Oid(Shared(data), Oid);
-- attach Oid we have got from Param to data
for i in 1..3 loop
Shared’READ(CoKe_Strm’access, data);
-- read data from VSM
Text_IO.Put_Line(integer’IMAGE(CoKeInt_to_Int(data)));
end loop;
Process_Commit;
-- exit in commit state
end Consumer;
1.3 Ada CORSO绑定的优缺点
- 缺点 :Ada的任务不能直接用作CORSO进程,但可以在CORSO进程中自由使用任务。Java等语言也存在同样的问题。
-
优点
:
- Ada的读写属性对于合并对共享内存池中对象的访问非常有用。
- 该绑定以直接的方式为Ada添加了面向事务、容错的分布式对象,而无需扩展Ada语言。
- Ada的泛型和标记类型为正确建模IDL类型、共享对象范式和事务之间的相互依赖关系提供了很好的方法。
2. 多模式实时系统中的天花板协议
2.1 固定优先级调度与优先级继承协议
固定优先级调度是实现实时系统的重要方法,它通过优先级继承协议支持资源管理,并能对操作模式进行建模。其中,即时继承优先级天花板协议(IIPCP)是基于为资源分配一个优先级,当任务访问资源时会立即继承该优先级,这个优先级被称为资源的天花板优先级。IIPCP可以防止运行时出现无界优先级反转,允许进行静态分析以确定任务的最坏情况阻塞时间。
2.2 多模式实时系统的特点
许多实时系统具有多种互斥的操作模式,每个操作模式由一组活动任务来表征。这些任务在不同模式下可能活跃或不活跃,并且任务在不同模式下可能具有不同的时间行为,如不同的周期或截止时间。例如,飞机的控制系统可以在起飞、平飞和降落等模式下工作,使用不同的软件组件来操作不同的资源。
2.3 操作模式对天花板优先级的影响
不同的操作模式可能导致资源的天花板优先级不同,因为不同模式下活跃的任务不同。此外,任务属性的变化(如截止时间或周期)可能导致任务在不同模式下具有不同的优先级。一种管理多模式实时系统中天花板优先级的方法是应用所谓的“天花板的天花板”,即从所有可能操作模式的系统分析中得出的最高天花板。但这可能导致过度的(尽管有界)优先级反转,使系统不可调度。
2.4 Ada和POSIX中的实现问题
- Ada :在Ada中,共享资源通过受保护对象(POs)实现。可以使用Ada编译指示支持IIPCP,并为每个PO静态分配一个优先级(天花板)。但在运行时不能更改PO的优先级,因为这会带来过高的复杂性和语义歧义。
-
POSIX
:POSIX标准中提到了
PRIO_PROTECT
选项,提供了pthread_mutex_setprioceiling()
函数来动态更改互斥锁的天花板优先级。但实际上,很多POSIX实现要么不支持该选项,要么只是更改了天花板数字,而没有考虑系统的状态,这可能会引入长延迟。
2.5 系统模型与QUISAP实现
2.5.1 系统模型
实时系统由周期性和突发性任务以及代表资源的对象组成,任务可以共享对象,系统负责提供互斥保护以防止竞争条件。
2.5.2 QUISAP实现
该模型已实现为一个名为QUISAP的实时系统架构。在QUISAP中:
- 任务通过Ada任务实现,任务类型定义了任务的行为,并通过参数实例化为新任务。
- 允许定义操作模式,操作模式在属于每个模式的任务子集和/或任务的时间属性上有所不同。
- 通过两个预定义的Ada编译指示实现确定性:
-
pragma Task_Dispatching_Policy(Fifo_Within_Priorities)
确保高优先级任务在活跃时总是抢占低优先级任务。
-
pragma Locking_Policy(Ceiling_Locking)
确保对象的行为符合IIPCP,避免无界优先级反转。
- 使用具有最高优先级的受保护对象来控制任务的正确执行,并检测和处理模式更改,利用Ada的异步控制转移(ATC)功能提供模式更改。
2.6 天花板优先级与模式更改的结合问题
2.6.1 问题描述
以一个包含两个操作模式(M1和M2)、四个任务(T1到T4)和一个受保护对象PO的实时系统为例,具体数据如下表所示:
| 任务 | 模式M1中的优先级 | 模式M2中的优先级 | 是否使用受保护对象 |
| ---- | ---- | ---- | ---- |
| T1 | 1 | 1 | 是 |
| T2 | 2 | 2 | 是 |
| T3 | 3 | 3 | 否 |
| T4 | 不活跃 | 4 | 是 |
静态分析表明,模式M1中受保护对象的天花板优先级为2(CPM1 = 2),模式M2中为4(CPM2 = 4)。但在Ada中无法动态更改受保护对象的优先级,因此需要为每个受保护对象分配一个适用于所有操作模式的唯一天花板优先级。这个优先级是“天花板的天花板”,计算公式为:
[CP = \max_{m \in M} CP_m]
在这个例子中,受保护对象的天花板优先级为4。这在模式M2中是有效的,但在模式M1中,任务T3可能需要等待T2或T1释放受保护对象,因为它们在使用PO时将以优先级4执行,这与模式M1的静态分析结果相悖。如果T3被T1或T2使用PO阻塞,它将不可调度。
2.6.2 问题解决思路
虽然应用上述公式是解决方案的开始,但还需要进一步考虑。应用该公式对模式M2的分析没有影响,但会对模式M1产生负面影响。因此,需要寻找其他方法来解决这个问题。
下面是这个示例系统的mermaid流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(模式M1):::process
A --> C(模式M2):::process
B --> D{T3是否被阻塞?}:::decision
D -->|是| E(T3不可调度):::process
D -->|否| F(T3可调度):::process
C --> G(正常运行):::process
E --> H([结束]):::startend
F --> H
G --> H
综上所述,在多模式实时系统中,天花板优先级的管理是一个复杂的问题,需要综合考虑各种因素,以确保系统的可调度性。
3. 解决多模式实时系统中天花板优先级问题的方法
3.1 解决方案概述
为了解决多模式实时系统中使用单一天花板优先级导致的任务调度问题,需要寻找合适的方法来平衡不同模式下的资源使用和任务优先级。下面将针对之前示例中出现的问题,进一步探讨具体的解决思路和方法。
3.2 特殊情况与新解决方案
3.2.1 特殊情况描述
在某些情况下,即使采用了“天花板的天花板”方法,仍然可能存在一些特殊情况无法得到有效解决。例如,当某个任务在不同模式下的优先级和资源使用情况非常复杂时,单一的天花板优先级可能会导致更多不必要的阻塞。在上述示例中,模式M1下任务T3因为统一的天花板优先级4而可能被T1或T2阻塞,从而变得不可调度,这就是一种特殊情况。
3.2.2 新解决方案
为了解决这些特殊情况,需要提出一种更通用的解决方案。可以考虑在不同模式下动态调整任务的优先级和资源的使用策略。具体来说,可以在模式切换时,根据当前模式下的任务集合和资源需求,重新计算每个任务的优先级和资源的天花板优先级。
以下是一个简单的流程说明:
1.
模式切换检测
:当系统检测到模式切换时,触发优先级和天花板优先级的重新计算。
2.
任务和资源信息收集
:收集当前模式下所有任务的优先级、资源使用情况等信息。
3.
天花板优先级重新计算
:根据收集到的信息,为每个资源重新计算天花板优先级。可以采用类似“天花板的天花板”的方法,但只考虑当前模式下的任务。
4.
任务优先级调整
:根据新的天花板优先级,调整每个任务的优先级,确保任务之间的优先级关系符合当前模式的需求。
5.
资源分配和任务调度
:根据新的优先级和天花板优先级,进行资源分配和任务调度。
3.3 解决方案的实施步骤
为了更清晰地展示解决方案的实施过程,下面将详细列出具体的步骤:
步骤 | 操作内容 |
---|---|
1 | 定义一个模式切换检测机制,例如使用事件触发或定时检查。 |
2 | 在模式切换时,收集当前模式下所有任务的信息,包括优先级、资源使用情况等。可以使用数据结构(如数组或链表)来存储这些信息。 |
3 | 根据收集到的信息,为每个资源重新计算天花板优先级。可以编写一个函数来实现这个计算过程。 |
4 | 根据新的天花板优先级,调整每个任务的优先级。可以使用优先级队列或其他数据结构来管理任务的优先级。 |
5 | 在资源分配和任务调度时,使用新的优先级和天花板优先级。可以编写调度算法来实现资源的合理分配和任务的有效调度。 |
3.4 示例代码实现
以下是一个简单的示例代码,展示了如何实现模式切换时的优先级和天花板优先级的重新计算:
-- 假设这是一个模式切换的过程
procedure Mode_Switch(New_Mode: Integer) is
-- 定义任务和资源的信息
type Task_Info is record
Priority: Integer;
Uses_Resource: Boolean;
end record;
type Resource_Info is record
Ceiling_Priority: Integer;
end record;
-- 存储当前模式下的任务和资源信息
Task_List: array(1..4) of Task_Info;
Resource_List: array(1..1) of Resource_Info;
-- 重新计算天花板优先级的函数
function Recalculate_Ceiling_Priority return Integer is
Max_Priority: Integer := 0;
begin
for I in Task_List'Range loop
if Task_List(I).Uses_Resource then
if Task_List(I).Priority > Max_Priority then
Max_Priority := Task_List(I).Priority;
end if;
end if;
end loop;
return Max_Priority;
end Recalculate_Ceiling_Priority;
-- 调整任务优先级的函数
procedure Adjust_Task_Priorities is
begin
-- 根据新的天花板优先级调整任务优先级
-- 这里可以添加具体的调整逻辑
null;
end Adjust_Task_Priorities;
begin
-- 根据新的模式更新任务和资源信息
case New_Mode is
when 1 =>
-- 模式M1的任务和资源信息
Task_List(1).Priority := 1;
Task_List(1).Uses_Resource := True;
Task_List(2).Priority := 2;
Task_List(2).Uses_Resource := True;
Task_List(3).Priority := 3;
Task_List(3).Uses_Resource := False;
Task_List(4).Priority := 0; -- 不活跃
Task_List(4).Uses_Resource := False;
when 2 =>
-- 模式M2的任务和资源信息
Task_List(1).Priority := 1;
Task_List(1).Uses_Resource := True;
Task_List(2).Priority := 2;
Task_List(2).Uses_Resource := True;
Task_List(3).Priority := 3;
Task_List(3).Uses_Resource := False;
Task_List(4).Priority := 4;
Task_List(4).Uses_Resource := True;
when others =>
null;
end case;
-- 重新计算天花板优先级
Resource_List(1).Ceiling_Priority := Recalculate_Ceiling_Priority;
-- 调整任务优先级
Adjust_Task_Priorities;
end Mode_Switch;
3.5 解决方案的效果评估
为了评估解决方案的效果,可以从以下几个方面进行考虑:
- 任务可调度性 :通过分析任务的执行时间、截止时间和阻塞时间,评估任务的可调度性是否得到改善。例如,在上述示例中,模式M1下任务T3的可调度性是否得到提高。
- 资源利用率 :观察资源的使用情况,评估资源的利用率是否得到优化。例如,资源是否能够更合理地分配给不同的任务。
- 系统响应时间 :测量系统对模式切换的响应时间,评估系统的实时性能是否受到影响。
以下是一个简单的mermaid流程图,展示了解决方案的整体效果评估过程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(实施解决方案):::process
B --> C{任务可调度性是否改善?}:::decision
C -->|是| D(资源利用率是否优化?):::decision
C -->|否| E(调整解决方案):::process
D -->|是| F(系统响应时间是否合理?):::decision
D -->|否| E
F -->|是| G(解决方案有效):::process
F -->|否| E
E --> B
G --> H([结束]):::startend
4. 总结
本文主要探讨了Ada编程中CORSO应用和多模式实时系统中的天花板优先级问题。在CORSO应用方面,介绍了如何在LSYS中注册进程,以及生产者/消费者示例的实现,同时分析了Ada CORSO绑定的优缺点。在多模式实时系统中,详细阐述了天花板协议的原理、操作模式对天花板优先级的影响,以及Ada和POSIX中的实现问题。针对天花板优先级与模式更改结合时出现的问题,提出了一种通用的解决方案,并详细描述了实施步骤和效果评估方法。
通过本文的研究,可以得出以下结论:
- Ada CORSO绑定为Ada世界打开了虚拟共享内存的领域,但也存在一些局限性,如Ada任务不能直接用作CORSO进程。
- 在多模式实时系统中,天花板优先级的管理是一个复杂的问题,单一的天花板优先级可能会导致任务调度问题。
- 通过动态调整任务的优先级和资源的使用策略,可以有效解决多模式实时系统中天花板优先级的问题,提高任务的可调度性和资源的利用率。
未来的研究可以进一步探索更高效的优先级调整算法和资源分配策略,以适应更复杂的实时系统需求。同时,可以考虑将这些方法应用到实际的工程项目中,验证其有效性和实用性。