新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > ucOS- II中设计了五种通讯机制

ucOS- II中设计了五种通讯机制

作者:时间:2016-11-27来源:网络收藏
在ucOS- II中设计了五种通讯机制,或者说是同步机制,分别是信号量(semaphore),互斥体(mutual exclusion semaphore),事件组(event flag),邮箱(message box)和队列(queue),而事件(event)则是这几种通讯机制的核心,这几天学习了一下这几种机制,总结一下先,呵呵。
1. 先总结一下作为核心的事件控制机制:
1.1 数据结构设计:类似于任务就绪表一样,作者设计了等待任务表,表的作用原理和任务就绪表完全一样,甚至共用了OSMapTbl和OSUnMapTbl这 两个表,不用之处,任务就绪表用来查询就绪的任务中优先级最好的那个,而等待任务表用来查询等待事件的任务中优先级最高的那个,类似于就绪表,设计了两个 变量:OSEventGrp和OSEventTbl[],不同的时候这两个变量被设计进时间控制块(event control block ECB)中,也就是说对于每个事件(上述五种)都有一个等待任务表。对于ECB,还有其他三个变量:OSEventType(用来标识是上述五种的哪一 种), OSEventCnt(信号量和互斥体会用到)和OSEventPtr(在邮箱中用来存放消息,在队列中用来存放队列块的指针)。对于事件组来说,作者设 计了另一套数据结构,而没有用到ECB。
1.2 事件控制的核心函数有四个,基本上就是对等待任务表的操作,这些函数将作为上述五种通讯机制的核心功能:
1.2.1OS_EventWaitListInit:初始化等待任务表, 很简单。
1.2.2 OS_EventTaskRdy:首先找到等待该事件的优先级最高的任务,将其从等待任务表中移走,然后更新该任务的TCB,最高根据TCB的OSTCBStat变量更新任务就绪表(如果该任务没有等待任何事件,那么就把它加入任务就绪表)。
1.2.3 OS_EventTaskWait:首先把当前任务从任务就绪表中移走,然后把当前任务加进这个事件的等待任务表。这个函数其实就是挂起当前任务!
1.2.4 OS_EventTO:超时处理函数,将当前任务从等待任务列表中移走,并更新TCB使其进入就绪状态,值得注意的是,它并不更新就绪任务表!!!
2. 信号量的实现
信号量的用途主要有三个:第一, 表示一个或多个事件的发生; 第二, 表示共享资源的可用(二值信号量); 第三, 表示n个相同资源的访问(多值信号量)(这是书上的说法,我认为应该表述为: 表示共享资源对n个任务的可用)。
2.1 数据结构设计:信号量只是用到ECB,一个信号量用一个ECB表示,没有用到其他数据结构。其中ECB的OSEventPtr变量没有用到,只是简单的将其设为0,因此信号量是比较简单的一个通讯机制。
2.2 核心函数主要有四个:
2.2.1 OSSemCreate:创建一个信号量:首先从事件控制块缓冲区中得到一个ECB,然后初始化这个ECB,对其中等待任务表的初始化用到OS_EventWaitListInit。
2.2.2 OSSemDel:销毁一个信号量:有两种情况, 第一,只有在没有任务等待该信号量的时候才删除;第二,不管有没有任务等待该信号量都强制删除;对于第一种情况,用OS_DEL_NO_PEND进行标 识,这个时候,如果确实没有任务在等待该信号量,将ECB归还到ECB缓冲区,然后返回; 如果有任务在等待该信号量,直接返回错误标识,以告诉调用者删除失败。 对于第二种情况,用OS_DEL_ALWAYS进行标识,首先用OS_EventTaskRdy将等待任务表中的所有任务都移走,然后将该ECB归还到 ECB缓冲区。这个时候要做判断如果刚刚有任务在等待该信号量(这个判断在移走之前已经做好),就必须重新调度:OS_Sched!所以,如果当前任务不是优先级最高的任务,那么这个函数将会被挂起,呵呵。
2.2.3 OSSemPend:该函数可能会引起当前任务被挂起:首先判断该信号量是否可用,也就是ECB的OSEventCnt是否不为0,如果可用的话更新 ECB然后返回,任务继续执行;如果不可用,那么就更新当前任务的TCB,然后用OS_EventTaskWait挂起任务,然后重新调度。这时,该函数 将可能被挂起,直到当前任务获得该信号量从而恢复执行。然后该函数判断当前任务继续执行的原因,如果是超时的话,调用OS_EventTO,如果是得到信 号量而返回的话,更新当前TCB,然后返回。另外,这也就是OS_EventTO不更新就绪表的原因——本身已经在运行了呀,呵呵。
2.2.4 OSSemPost:该函数释放该信号量,从而可以使正在等待该信号量的任务恢复执行: 首先判断等待任务表中是否有任务正在等待该信号量,如果有的话就通过OS_EventTaskRdy使等待任务表中优先级最高的任务不再等待该信号量(具 体的操作如上面所述)。接下来(不管有没有任务正在等待该信号量)就更新ECB,其实就是将其中的变量OSEventCnt加1。
前面对信号量 做了一个简单的总结,下面对互斥体,邮箱和队列以及事件组做一个总结,由于事件组没有用到ECB,而其他的都有用到ECB,所以最后总结事件组,也就是 说,除了事件组会从一个作者专门设计的系统缓冲区申请用到的数据结构,其他的都会从ECB缓冲区中申请ECB。
3. 互斥体的实现
从其名字,mutual exclusion semaphore,可以看出来,其实互斥体属于信号量的一种,其实它是一个二值信号量,之所以把它单独拿出来设计,主要是为了解决任务优先级反转的问题 ——当该互斥体被一个任务占用的时候,如果有更高的优先级任务等待该互斥体,那么将占用该互斥体的任务的优先级提升到预先设定的那个比较高的优先级,从而 能改善优先级反转的问题,但是不能完全去掉,呵呵。
3.1 数据结构的设计:
和信号量一样,互斥体只用到ECB这一数据结构, 不同的是,由于它主要被设计用来解决优先级反转的问题,每一个互斥体都会一个实现设定的优先级联系起来,这个优先级应该尽量比较高,这样,拥有这个互斥体 的任务将会先被处理,从而改善优先级反转的问题。ECB中,OSEventType用来标识该事件对象是个互斥体;OSEventCnt的高8位用来存放 与该互斥体关联的优先级,而低8位存放拥有该互斥体的任务优先级;OSEventPtr存放拥有该互斥体的任务的TCB指针;剩下的等待任务表和信号量一 样,没任何区别。
3.2 核心函数和信号量一样有四个,但是由于每个互斥体都与一个任务优先级联系起来,实现有一些复杂:
3.2.1 OSMutexCreate:创建一个互斥体:首先判断该优先级有没有被任务占用,如果有的话,创建失败;然后从ECB缓冲区中取一个ECB; 最后初始化得到的ECB,值得注意的是,ECB的变量OSEventCnt的高8位用来存放关联的优先级,当然,等待任务表还是用 OS_EventWaitListInit来初始化。
3.2.2 OSMutexDel: 删除一个互斥体:其实现与信号量基本一样,唯一的不用还是由于其关联了一个任务优先级,删除的时候应该将优先级重新标识为可用。
3.2.3 OSMutexPend:等待一个互斥体:首先判断是否该互斥体可用,如果可用的的话就用当前任务的优先级和TCB更新ECB,表明该互斥体已经被当前任务占用,直接返回,这种情况最简单; 如果互斥体已经被其他任务占用:首先判断占用该互斥体的任务的优先级是不是比当前任务的优先级低,如果是的话就要做提升占用该互斥体任务优先级的操作,这也就是互斥体的主要用途——更新就绪任务表,更新该任务TCB,更新任务优先级标识表OSTCBPrioTbl。剩下的处理与信号量的OSSemPend的处理完全一致:更 新当前任务的TCB,然后用OS_EventTaskWait挂起任务,然后重新调度。这时,该函数将可能被挂起,直到当前任务获得该互斥体从而恢复执 行。然后该函数判断当前任务继续执行的原因,如果是超时的话,调用OS_EventTO,如果是得到该互斥体而返回的话,更新当前TCB,然后返回。
3.2.4 OSMutexPost:释放一个互斥体,注意,只要占用该互斥体的任务能够释放该互斥体!首先检查当前任务是否占用该互斥体,如果不是的话直接返回错误;然后判断当前的任务优先级是否被提升过,如果是的话,就做恢复当前任务的优先级——更新就绪任务表,更新当前任务TCB,更新任务优先级标识表OSTCBPrioTbl;接下来,通过等待任务表判断是否有任务在等待该互斥体,如果有的话通过OS_EventTaskRdy其中优先级最高的任务,然后将该互斥体标识为这个优先级最高的任务所占用, 如果没有任务在等待该互斥体,就重置它。
4. 邮箱的实现
邮箱(mail box)主要用来从一个任务向另外一个任务发送一个消息,其实就是一个指针,因此,与信号量和互斥提稍有不同,信号量和互斥体用来同步对资源的访问,而这 个资源在信号量和互斥体中是没有体现的,换句话说,从信号量和互斥体的ECB中不能看出是在同步哪些资源,而邮箱的话,这个资源(也就是消息)被放在 ECB中!总的说来,邮箱的实现相对来说很简单!
4.1 数据机构的设计:
邮箱也只用到ECB,和信号量以及互斥体不同的是,邮箱没有用到OSEventCnt,而是使用OSEventPtr来存放消息(指针)。其他的和信号量于互斥体相同。
4.2 核心函数也是四个,与信号量和互斥体一样:
4.2.1 OSMboxCreate:创建一个邮箱:实现很简单,首先申请一个ECB,然后初始化这个ECB,其中用OS_EventWaitListInit初始化等待任务表。
4.2.2 OSMboxDel:删除一个邮箱:与信号量中OSSemDel完全相同。
4.2.3 OSMboxPend:等待一个邮箱消息:首先检查该邮箱中是否有消息,如果有的话取出消息,然后返回; 如果邮箱中没有消息,那么更新当前任务TCB,并用OS_EventTaskWait挂起当前任务,然后重新调度:OS_Sched! 这个时候当前任务将会被挂起,直到等待的消息来临或者超时才得意恢复执行,之后,它检查邮箱中是否有消息,如果有的话,取走消息,正常返回;如果邮箱中仍 然没有消息,那么当前任务恢复执行是因为超时,于是返回超时错误!
上一页 1 2 下一页

关键词: ucOS-I通讯机

评论


相关推荐

技术专区

关闭