首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

μC/OS-III对信号量的改进 01

μC/OS-III对信号量的改进 01

引言
μC/OS是一个基于优先级调度的可剥夺型实时多任务内核。在多任务的实时内核中,信号量是常用的机制,可以用来实现对共享资源的访问、任务之间的通信和同步,以及任务和中断的同步等功能。μC/OS—II中提供了等待和释放信号量等最基本的服务,而在μC/OS—III中,对信号量的使用增加了一些可选的模式,如非阻塞等待、释放但不进行任务调度等,提高了使用的灵活性。更重要的是,在μC/OS—III中还新增了任务内嵌的信号量,用户程序无需建立信号量便可和任务直接通信,比普通信号量更加简单高效。本文将分析对比μC/OS—II和μC/OS—III中信号量内部结构的差异以及μC/OS—III新增的特性。

1 μC/OS—II中信号量内部结构
在μC/OS—II中,信号量直接使用内核的数据结构OS EVENT,其内部结构如下:


其中,和信号量相关的最重要的就是OSEventCnt、OSEventGrp和OSEventTbl[]。OSEventCnt记录的是信号量的有效值。OSEventTbl[]是一个位映射表,以64级优先级为例,OSEventTbl[]将是一个8×8的位映射表,如果某优先级下有任务在等待该事件,则OSEventTbl[]中对应的位将被置1。为了加快查询过程,又将64级优先级分为8组,用一个8位的整型OSEventGrp来记录每一组的状态。可见,OSEventGrp和OSEve ntTbl[]跟就绪表中的OSRdyGrp和OSRdyTbl[]结构是一模一样的,区别仅仅在于前者记录的是等待该事件的任务的状态,而后者记录的是系统中就绪的任务的状态。而两者的查找过程是一样的,都是通过“掩码表”来快速得到列表中优先级最高的任务。
μC/OS—II提供的信号量相关的最常用的几个API函数如下:

在使用信号量前必须先新建一个信号量,并指定其初始值。当信号量用于对共享资源的访问时,该值应初始化为实际可用的共享资源数;当信号量用来实现任务的同步,则初始值应设为0。调用等待信号量的OSSemPend()函数时可以指定超时选项timeout,在指定的时间内如果没有获得信号量则任务会超时返回。释放信号量时,如果有任务在等待,内核会通过查找OSEventGrp和OSEventTbl[]获得等待任务中优先级最高的任务,该任务将获得信号量从而转入就绪态,内核会进行任务调度。如果获得信号量的任务比正在执行的任务优先级还高,则会进行任务切换。

2 μC/OS-Ⅲ中信号量内部结构
在μC/OS—III中,信号量类型的结构有所变化,并没有和μC/OS—II一样继续采用和“就绪表”类似的结构,而是采用一个“等待列表”的数据结构来记录等待信号量的任务。其数据结构如下:

从上述结构可以看出,μC/OS—III的信号量结构中新增了一个时间戳TS,用来记录最近一次释放信号量(或者是取消等待、删除信号量)的时间。而等待信号量的任务列表则通过一个新的数据结构OS_PEND_LIST来记录,如图1所示。



OS_PEND_LIST包括3个数据域:NbrEntries用来记录等待列表中的条目数,也就是等待的任务数目;HeadPtr和TailPtr构成一个双向链表,指向的是OS_PEND_DATA类型的结构体。OS_PEND_DATA是μC/OS—III内部的一个数据类型,每当任务因等待信号量而被挂起时,内核就会新建一个对应的OS_PEND_DATA类型的数据块并插入到信号量的等待列表OS_PEND_LIST所包含的双向链表中。OS_PEND_DATA结构体包含指向等待任务的OS_TCB的指针以及其他数据域。在这里,最重要的细节是,μC/OS-III是按照任务优先级从高到低的顺序来排列双向链表中的OS_PE ND_DATA数据块的。也就是说,每当有一个新的OS_PEND_DATA数据块需要插入到双向链表时(也就是任务因等待信号量而被挂起时),内核会从链表头部开始扫描各个OSPEND_DATA数据块所对应的等待任务的优先级(通过OS_PEND_DATA数据块内部的TCBPtr指针可以从任务控制块内部获得任务的优先级),直到找到比当前需要插入的任务的优先级低的任务,然后把新的OS PEND_DATA数据块插入到该位置前。如果链表中已有和需要插入的任务优先级相同的任务,则新插入的任务放到优先级相同的任务后。道理很简单,优先级相同,晚到的任务没有任何理由比早到的任务先获得信号量。基于上述排列方法,位于双向链表头部的任务总是等待的任务中优先级最高的。因此,当用户释放信号量时,总是双向链表头部的任务获得信号量,而不必再执行“查找最高优先级”的过程了。

返回列表