新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II的任务之间的通讯与同步

μC/OS-II的任务之间的通讯与同步

作者: 时间:2016-10-08 来源:网络 收藏

表T6.1OSMapTbl[]

从等待任务列表中删除一个任务的算法则正好相反,如程序清单L6.3所示。

程序清单L6.3从等待任务列表中删除一个任务

if((pevent->OSEventTbl[prio>>3]=~OSMapTbl[prio0x07])==0){

pevent->OSEventGrp=~OSMapTbl[prio>>3];

}

该代码清除了任务在.OSEventTbl[]中的相应位,并且,如果其所在的组中不再有处于等待该事件的任务时(即.OSEventTbl[prio>>3]为0),将.OSEventGrp中的相应位也清除了。和上面的由任务优先级确定该任务在等待表中的位置的算法类似,从等待任务列表中查找处于等待状态的最高优先级任务的算法,也不是从.OSEventTbl[0]开始逐个查询,而是采用了查找另一个表OSUnMapTbl[256](见文件OS_CORE.C)。这里,用于索引的8位分别代表对应的8组中有任务处于等待状态,其中的最低位具有最高的优先级。用这个值索引,首先得到最高优先级任务所在的组的位置(0~7之间的一个数)。然后利用.OSEventTbl[]中对应字节再在OSUnMapTbl[]中查找,就可以得到最高优先级任务在组中的位置(也是0~7之间的一个数)。

这样,最终就可以得到处于等待该事件状态的最高优先级任务了。程序清单L6.4是该算法的具体实现代码。

程序清单L6.4在等待任务列表中查找最高优先级的任务

y=OSUnMapTbl[pevent->OSEventGrp];

x=OSUnMapTbl[pevent->OSEventTbl[y]];

prio=(y3)+x;

举例来说,如果.OSEventGrp的值是01101000(二进制),而对应的OSUnMapTbl[.OSEventGrp]值为3,说明最高优先级任务所在的组是3。类似地,如果.OSEventTbl[3]的值是11100100(二进制),OSUnMapTbl[.OSEventTbl[3]]的值为2,则处于等待状态的任务的最高优先级是3×8+2=26。

在μC/OS-II中,事件控制块的总数由用户所需要的信号量、邮箱和消息队列的总数决定。

该值由OS_CFG.H中的#defineOS_MAX_EVENTS定义。 在调用OSInit()时 (见3.11节, μC/OS-II

的初始化),所有事件控制块被链接成一个单向链表——空闲事件控制块链表(图F6.3)。每

当建立一个信号量、邮箱或者消息队列时,就从该链表中取出一个空闲事件控制块,并对它进

行初始化。因为信号量、邮箱和消息队列一旦建立就不能删除,所以事件控制块也不能放回到

空闲事件控制块链表中。

图F6.3空闲事件控制块链表——Figure6.3

对于事件控制块进行的一些通用操作包括:

y 初始化一个事件控制块

y 使一个任务进入就绪态

y 使一个任务进入等待该事件的状态

y 因为等待超时而使一个任务进入就绪态

为了避免代码重复和减短程代码长度,μC/OS-II将上面的操作用4个系统函数实现,它们是:OSEventWaitListInit(),OSEventTaskRdy(),OSEventWait()和OSEventTO()。

6.2 初始化一个事件控制块,OSEventWaitListInit()

程序清单L6.5是函数OSEventWaitListInit()的源代码。当建立一个信号量、邮箱或者消息队列时,相应的建立函数OSSemInit(),OSMboxCreate(),或者OSQCreate()通过调用

OSEventWaitListInit()对事件控制块中的等待任务列表进行初始化。该函数初始化一个空的等

待任务列表,其中没有任何任务。该函数的调用参数只有一个,就是指向需要初始化的事件控

制块的指针pevent。

程序清单L6.5初始化ECB块的等待任务列表

voidOSEventWaitListInit(OS_EVENT*pevent)

{

INT8Ui;

pevent->OSEventGrp=0x00;

for(i=0;i

pevent->OSEventTbl[i]=0x00;

}

}

6.3 使一个任务进入就绪态,OSEventTaskRdy()

程序清单L6.6是函数OSEventTaskRdy()的源代码。当发生了某个事件,该事件等待任务列表中的最高优先级任务(HighestPriorityTask–HPT)要置于就绪态时,该事件对应的OSSemPost(),OSMboxPost(),OSQPost(),和OSQPostFront()函数调用OSEventTaskRdy()实现该操作。换句话说,该函数从等待任务队列中删除HPT任务(HighestPriorityTask),并把该任务置于就绪态。图F6.4给出了OSEventTaskRdy()函数最开始的4个动作。

该函数首先计算HPT任务在.OSEventTbl[]中的字节索引[L6.6/F6.4(1)],其结果是一个从0到OS_LOWEST_PRIO/8+1之间的数,并利用该索引得到该优先级任务在.OSEventGrp中的位屏蔽码[L6.6/F6.4(2)](从表T6.1可以得到该值)。然后,OSEventTaskRdy()函数判断HPT任务在.OSEventTbl[]中相应位的位置[L6.6/F6.4(3)], 其结果是一个从0到OS_LOWEST_PRIO/8+1

之间的数,以及相应的位屏蔽码[L6.6/F6.4(4)]。根据以上结果,OSEventTaskRdy()函数计算

出HPT任务的优先级[L6.6(5)],然后就可以从等待任务列表中删除该任务了[L6.6(6)]。

任务的任务控制块中包含有需要改变的信息。知道了HPT任务的优先级,就可以得到指向该任务的任务控制块的指针[L6.6(7)]。因为最高优先级任务运行条件已经得到满足,必须停止OSTimeTick()函数对.OSTCBDly域的递减操作,所以OSEventTaskRdy()直接将该域清澈0[L6.6(8)]。因为该任务不再等待该事件的发生,所以OSEventTaskRdy()函数将其任务控制块中指向事件控制块的指针指向NULL[L6.6(9)]。如果OSEventTaskRdy()是由OSMboxPost()或者OSQPost()调用的,该函数还要将相应的消息传递给HPT,放在它的任务控制块中[L6.6(10)]。

另外,当OSEventTaskRdy()被调用时,位屏蔽码msk作为参数传递给它。该参数是用于对任务控制块中的位清零的位屏蔽码,和所发生事件的类型相对应[L6.6(11)]。最后,根据.OSTCBStat判断该任务是否已处于就绪状态[L6.6(12)]。如果是,则将HPT插入到μC/OS-II的就绪任务列表中[L6.6(13)]。注意,HPT任务得到该事件后不一定进入就绪状态,也许该任务已经由于其它



关键词:

评论


相关推荐

技术专区

关闭