"); //-->
引言
μC/OS-II是源码公开的嵌入式实时操作系统内核,可用于8位、16位、32位嵌入式微处理器或DSP。μC/OS-II可以管理64个任务,各任务有自己单独的栈,采用基于剥夺的优先级调度策略,绝大多数服务的执行时间具有确定性。μC/OS-II自1992年问世以来已被成功地应用于各种系统,并且现在其安全性和稳定性已通过美国FAA认证。
μC/OSII使用优先级继承来管理共享资源,它能通过防止不受控制的优先级反转,来保障没有任务被无限制地阻塞。但是优先级继承不能阻止死锁的发生,并且它没有把任务的阻塞时间降到最低。事实上,当一个任务请求v个资源、并且和k个低优先级的任务发生竞争时,在最坏的情况下它有可能被阻塞min(v,k)\[1\]。这种不确定性限制了μC/OSII在一些既需要在多任务条件下使用共享资源,又要求有很高实时性能的系统上的应用。
本文将在μC/OSII 2.52中引入一种新的资源互斥协议——优先级天花板协议,并通过分析此协议的特点和μC/OSII的任务调度特点,使该协议在μC/OSII上得以实现,从而解决上述问题。
1优先级天花板协议
优先级天花板协议改进了优先级继承协议,它不仅能够防止死锁的发生,还进一步减少了任务的阻塞时间。当用优先级天花板协议控制资源的使用时,一个高优先级的任务最多被低优先级任务阻塞一次,阻塞时间最长等于比它优先级低的任务的临界区的最长执行时间,即max(e1 ,e2,ei,…),其中ei是第i个任务临界区的执行时间\[1\]。
优先级天花板协议的调度规则和资源分配规则如下。
(1) 调度规则
① 当任务不占有任何资源时,运行在原来的优先级上。相同优先级的任务基于FIFO规则调度。
② 每个占有资源的任务的优先级等于它所占有的所有资源的天花板优先级中最高的那个优先级(资源的天花板优先级等于所有将要使用它的任务中优先级最高的那个任务的优先级)。
(2) 分配规则
任务不管什么时候请求资源都可以得到满足。
优先级天花板的本质是让占有资源的任务尽快执行完,并释放资源,从而使与其竞争资源的高优先级任务尽快地得到执行,并通过良好定义的调度规则使任务不会交错占有资源而形成环路等待,从而保证死锁不会发生[1]。
2优先级天花板协议在μC/OSII上实现优先级天花板协议中,资源的优先级是根据任务的优先级来定义的,这其中隐含了两个假设,需要在μC/OSII的实现中得到满足。首先,任务对资源的需求必须是事先知道的;其次,任务的优先级必须是固定的。同时,μC/OSII不允许不同任务有相同的优先级,这就要求对优先级天花板协议做出修改。
需要增加四个API来实现协议的创建和删除,并使用该协议对共享资源进行申请和释放。这四个API分别为OSPriCeilingCreate()、OSPriCeilingDel()、OSPriCeilingPend()、OSPriCeilingPost( )。
2.1修改优先级天花板协议
μC/OSII不允许任务有相同的优先级,所以也就不存在相同优先级的任务有基于FIFO规则调度的问题。优先级天花板协议对资源的天花板优先级的定义是:资源的天花板优先级等于所有将要使用它的任务中优先级最高的那个任务的优先级。从上面的调度规则可知,当一个任务占有资源时,会继承此资源的天花板优先级,可能出现两个任务具有相同优先级的情况,这是μC/OSII所不允许的。我们可以保留一个略高于所有使用此资源的任务优先级的优先级作为此资源的天花板优先级,把这个优先级称作PCP(Priority Ceiling Priority)。例如,有T1、T2、 T3三个任务,T1不使用任何资源,T2、T3都需要使用资源R1,三个任务的优先级从高到低分别为11,13,15,那么我们可以保留12(略高于T2的优先级13)作为R1的PCP。这样的修改既满足了μC/OSII对任务优先级的限制,又不会改变优先级天花板的正确语义。
修改后的优先级天花板协议的规则如下。
(1) 调度规则
① 当任务不占有任何资源时,运行在原来的优先级上。
② 每个占有资源的任务的优先级等于它所占有的所有资源的天花板优先级中最高的那个优先级。资源的天花板优先级等于PCP。
(2) 分配规则
任务不管什么时候请求资源都可以得到满足。
2.2事件控制块的设计和任务控制块的修改
一个事件控制块(ECB)代表一个被多个任务共享的资源,μC/OSII内核通过事件控制块管理共享资源。内核需要通过事件控制块知道资源当前正在被哪个任务占有,所以在事件控制块中用一个8位无符号数来记录正在使用资源的任务ID;并且因为在μC/OSII中任务的优先级就是任务的ID,所以在任务释放资源时,这个数据还可以用来还原任务原先的优先级。这样可以在每个事件控制块中节约一个字节的空间,这对于一些内存很小的嵌入式系统来说是重要的。同样的原理用于事件控制块指针,它在资源空闲时将事件控制块链接成线性链表,在资源被分配给任务时用于保存此任务先前的事件控制块(这种机制支持了资源的嵌套使用,即任务先后申请不同的多个资源,然后以相反的顺序释放),如图1所示。μC/OSII最多允许64个任务优先级,所以在事件控制块中用一个8位无符号数表示资源的天花板优先级就足够了。从协议的分配规则可知,任务不会因为请求资源而被阻塞,所以优先级天花板协议的事件控制块不需要像其他事件控制块一样设置等待队列。优先级天花板协议事件控制块结构在系统启动时初始化成单向线性空闲链表。示例代码如下:typedef structos_priceiling_event{
INT8UOSEventPCP;/*资源的PCP */
INT8UOSEventPri;/*保存任务的优先级*/
structos_priceiling_event *OSEventPtr;
/*空闲时,指向链表中下一个事件控制块的指针,工作时
用于保存任务先前的事件控制块*/
} OS_PRICEILING_EVENT;如前所述,μC/OSII内核通过事件控制块管理共享资源,所以需要在任务控制块(TCB)中增加一个指向当前正在被任务使用的优先级天花板事件控制块的指针OSTCBCeilEventPtr,任务通过这个指针操纵当前的事件控制块。在多个资源被分配给一个任务后,事件控制块结构中的OSEventPtr指针和TCB中的OSTCBCeilEventPtr指针将形成一条事件控制块链,链头即为OSTCBCeilEventPtr,如图1所示。示例代码如下所示:#if OS_PRIORITYCEILING_EN > 0
/*如果不使用优先级天花板,则定义PRIORITYCEILING_EN小于等于0以减少每个TCB所占内存*/
OS_PRICEILING_EVENT * OSTCBCeilEventPtr;
#endif2.3用OSPriCeilingCreate()函数创建协议
任务要想使用优先级天花板协议管理共享资源的使用,必须先使用OSPriCeilingCreate()函数创建它。OSPriCeilingCreate()从空闲事件链表中摘下一个事件控制块结构,并将此结构中的OSEventPCP初始化成用户指定的PCP,并返回事件控制块指针给任务。如前所述,优先级天花板协议假设任务对资源的请求是预先知道的,所以必须通过函数参数指定PCP。
2.4用OSPriCeilingDel()函数删除协议
OSPriCeilingDel()函数中要实现的主要操作就是删除一个优先级天花板协议的实例,并回收事件控制块到空闲链表中。这个功能为任务提供一定方便的同时也带来了一定的危险性,因为多任务可能试图使用一个已经删除了的天花板协议,因此在使用时应该格外小心。
2.5用OSPriCeilingPend()函数申请资源
OSPriCeilingPend()和OSPriCeilingPost()是实现优先级天花板协议最核心的两个函数。优先级天花板协议的调度规则和分配规则都在这两个函数中实现。
当任务需要使用一个临界资源时,通过OSPriCeilingPend()函数申请该资源。它首先根据事件控制块指针取得资源的PCP,并将它和当前任务的优先级相比。如果任务的优先级比PCP低,那么根据优先级天花板协议的调度规则,要更新任务的优先级,使它等于PCP,并将当前事件控制块插入到由TCB中的OSTCBCeilEventPtr指向的事件控制块链表的前面。在更新任务的优先级之前,需要先保存任务原来的优先级,使得当任务释放此资源时可以回到取得此资源之前的优先级。接着要根据当前继承的优先级来重新计算任务控制块中的OSTCBY、OSTCBBitY、OSTCBX和OSTCBBitX四个数据域,这四个数据在进行任务调度时,快速地从就绪任务表中找出最高优先级的任务。
我们还需要在任务当前的优先级下从就绪表中删除该任务,并在新的优先级下将该任务插入到就绪表中,这是确保优先级天花板协议调度语义正确性的关键。这样做之后,该任务就不会再被较高优先级并且使用此资源的任务抢占而使互斥失败,因为在继承了此资源的PCP后,该任务就是所有使用此资源的任务中优先级最高的任务了。
以上所有操作所涉及的TCB、ECB等数据结构都是内核全局变量,其本身就是一种共享资源,如果一个任务没有完成对它们的全部操作之前就被剥夺执行权,那么这些数据结构就将处于不可预知的状态,引起系统崩溃。所以以上所有的操作都必须在中断关闭的情况下进行,也就是此时不允许任务调度。
假设某个优先级为15的任务T1,先后通过OSPriCeilingPend()申请到了共享资源R1(PCP为14)和R2(PCP为12),则此时T1的任务控制块和R1、R2的事件控制块的关系如图1所示。
图1T1申请到R1、R2后TCB和ECB结构示意图2.6释放资源——OSPriCeilingPost()函数的实现
任务通过OSPriCeilingPost()释放已取得的临界资源。此函数基本上执行和OSPriCeilingPend()函数相反的操作。如果任务的当前优先级等于此资源的PCP时,说明该任务的优先级是从这个资源继承而来的,此时任务需要回到原来的优先级,并在当前优先级下从任务就绪表中删除,在新的优先级下插入任务就绪表。这些操作也必须在关闭中断的情况下进行。这个函数和OSPriCeilingPend()函数最大的不同是它在最后需要进行一次调度,使高优先级的任务有机会得到处理器时间。
2.7需要修改的其他μC/OSII内核函数
如前所述,优先级天花板协议假设任务的优先级是固定的。但是μC/OSII允许任务调用OSTaskChangePrio()来改变自己或其他任务的优先级,所以需要修改此函数,使其能够判断用户是否在内核配置文件OS_CFG.H声明了要使用优先级天花板协议。如果条件成立,就阻止其改变优先级并返回错误信息。
3小结
优先级天花板协议不仅比优先级继承协议具有更小、更确定的高优先级任务阻塞时间,而且能够防止死锁的发生。通过在基于三星微处理器S3C44B0X(ARM7TDMI内核)的嵌入式开发板上对比优先级天花板协议和优先级继承协议,可以看到优先级天花板协议具有更快、更确定的时间性能。这些在一个实时嵌入式操作系统内核中都是至关重要的。但是在一个大型的复杂系统中,确定哪个任务是使用某个特定资源的所有任务中优先级最高的任务时,会有一些困难。在这种情况下,任务资源请求图可以为开发人员提供帮助。
参考文献
1Liu Jane W S.实时系统\[M\].北京:高等教育出版社,2002
2Labrosse Jean J.嵌入式实时操作系统μC/OSII \[M\]. 第2版. 北京:北京航空航天大学出版社,2003林游:硕士研究生,主要研究方向为嵌入式系统。韩志科:讲师,主要研究方向为嵌入式系统、计算机网络。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。