资源预览内容
第1页 / 共44页
第2页 / 共44页
第3页 / 共44页
第4页 / 共44页
第5页 / 共44页
第6页 / 共44页
第7页 / 共44页
第8页 / 共44页
第9页 / 共44页
第10页 / 共44页
亲,该文档总共44页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
文档供参考,可复制、编制,期待您的好评与关注! 第6章任务之间的通讯与同步6.0事件控制块ECB6.1初始化一个ECB块,OSEventWaitListInit()6.2使一个任务进入就绪状态,OSEventTaskRdy()6.3使一个任务进入等待状态, OSEventTaskWait()6.4由于等待超时将一个任务置为就绪状态, OSEventTO()6.5信号量6.5.1建立一个信号量, OSSemCreate()6.5.2等待一个信号量, OSSemPend()6.5.3发送一个信号量, OSSemPost()6.5.4无等待地请求一个信号量, OSSemAccept()6.5.5查询一个信号量的当前状态, OSSemQuery()6.6邮箱6.6.1建立一个邮箱,OSMboxCreate()6.6.2等待一个邮箱中的消息,OSMboxPend()6.6.3发送一个消息到邮箱中,OSMboxPost()6.6.4无等待地从邮箱中得到一个消息, OSMboxAccept()6.6.5查询一个邮箱的状态, OSMboxQuery()6.6.6使用邮箱作为二值信号量6.6.7使用邮箱实现延时,而不使用OSTimeDly()6.7消息队列6.7.1建立一个消息队列,OSQCreate()6.7.2等待一个消息队列中的消息,OSQPend()6.7.3向消息队列发送一个消息(FIFO),OSQPost()6.7.4向消息队列发送一个消息(LIFO),OSQPostFront()6.7.5无等待地从一个消息队列中取得消息, OSQAccept()6.7.6清空一个消息队列, OSQFlush()6.7.7查询一个消息队列的状态,OSQQuery()6.7.8使用消息队列读取模拟量的值6.7.9使用一个消息队列作为计数信号量 / 第6章 任务之间的通讯与同步在C/OS-II中,有多种方法可以保护任务之间的共享数据和提供任务之间的通讯。在前面的章节中,已经讲到了其中的两种:一是利用宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来关闭中断和打开中断。当两个任务或者一个任务和一个中断服务子程序共享某些数据时,可以采用这种方法,详见3.00节 临界段、8.03.02节OS_ENTER_CRITICAL() 和 OS_EXIT_CRITICAL()及9.03.02节 临界段,OS_CPU.H;二是利用函数OSSchedLock()和OSSchekUnlock()对C/OS-II中的任务调度函数上锁和开锁。用这种方法也可以实现数据的共享,详见3.06节 给调度器上锁和开锁。本章将介绍另外三种用于数据共享和任务通讯的方法:信号量、邮箱和消息队列。图F6.1介绍了任务和中断服务子程序之间是如何进行通讯的。一个任务或者中断服务子程序可以通过事件控制块ECB(Event Control Blocks)来向另外的任务发信号F6.1A(1)。这里,所有的信号都被看成是事件(Event)。这也说明为什么上面把用于通讯的数据结构叫做事件控制块。一个任务还可以等待另一个任务或中断服务子程序给它发送信号F6.1A(2)。这里要注意的是,只有任务可以等待事件发生,中断服务子程序是不能这样做的。对于处于等待状态的任务,还可以给它指定一个最长等待时间,以此来防止因为等待的事件没有发生而无限期地等下去。多个任务可以同时等待同一个事件的发生F6.1B。在这种情况下,当该事件发生后,所有等待该事件的任务中,优先级最高的任务得到了该事件并进入就绪状态,准备执行。上面讲到的事件,可以是信号量、邮箱或者消息队列等。当事件控制块是一个信号量时,任务可以等待它,也可以给它发送消息。图 6.1事件控制块的使用6.0 事件控制块ECBC/OS-II通过uCOS_II.H 中定义的OS_EVENT数据结构来维护一个事件控制块的所有信息程序清单L6.1,也就是本章开篇讲到的事件控制块ECB。该结构中除了包含了事件本身的定义,如用于信号量的计数器,用于指向邮箱的指针,以及指向消息队列的指针数组等,还定义了等待该事件的所有任务的列表。程序清单 L6.1是该数据结构的定义。程序清单 L6.1 ECB数据结构typedef struct void *OSEventPtr; /* 指向消息或者消息队列的指针 */ INT8U OSEventTblOS_EVENT_TBL_SIZE; /* 等待任务列表 */ INT16U OSEventCnt; /* 计数器(当事件是信号量时) */ INT8U OSEventType; /* 时间类型 */ INT8U OSEventGrp; /* 等待任务所在的组 */ OS_EVENT;.OSEventPtr指针,只有在所定义的事件是邮箱或者消息队列时才使用。当所定义的事件是邮箱时,它指向一个消息,而当所定义的事件是消息队列时,它指向一个数据结构,详见6.06节消息邮箱和6.07节消息队列。.OSEventTbl 和 .OSEventGrp 很像前面讲到的OSRdyTbl和OSRdyGrp,只不过前两者包含的是等待某事件的任务,而后两者包含的是系统中处于就绪状态的任务。(见3.04节 就绪表).OSEventCnt 当事件是一个信号量时,.OSEventCnt是用于信号量的计数器,(见6.05节信号量)。.OSEventType定义了事件的具体类型。它可以是信号量(OS_EVENT_SEM)、邮箱(OS_EVENT_TYPE_MBOX)或消息队列(OS_EVENT_TYPE_Q)中的一种。用户要根据该域的具体值来调用相应的系统函数,以保证对其进行的操作的正确性。每个等待事件发生的任务都被加入到该事件事件控制块中的等待任务列表中,该列表包括.OSEventGrp和.OSEventTbl两个域。变量前面的.说明该变量是数据结构的一个域。在这里,所有的任务的优先级被分成8组(每组8个优先级),分别对应.OSEventGrp中的8位。当某组中有任务处于等待该事件的状态时,.OSEventGrp中对应的位就被置位。相应地,该任务在.OSEventTbl中的对应位也被置位。.OSEventTbl数组的大小由系统中任务的最低优先级决定,这个值由uCOS_II.H中的OS_LOWEST_PRIO常数定义。这样,在任务优先级比较少的情况下,减少C/OS-II对系统RAM的占用量。当一个事件发生后,该事件的等待事件列表中优先级最高的任务,也即在.OSEventTbl中,所有被置1的位中,优先级代码最小的任务得到该事件。图 F6.2给出了.OSEventGrp和.OSEventTbl之间的对应关系。该关系可以描述为:当.OSEventTbl0中的任何一位为1时,.OSEventGrp中的第0位为1。当.OSEventTbl1中的任何一位为1时,.OSEventGrp中的第1位为1。当.OSEventTbl2中的任何一位为1时,.OSEventGrp中的第2位为1。当.OSEventTbl3中的任何一位为1时,.OSEventGrp中的第3位为1。当.OSEventTbl4中的任何一位为1时,.OSEventGrp中的第4位为1。当.OSEventTbl5中的任何一位为1时,.OSEventGrp中的第5位为1。当.OSEventTbl6中的任何一位为1时,.OSEventGrp中的第6位为1。当.OSEventTbl7中的任何一位为1时,.OSEventGrp中的第7位为1。图 F6.2 事件的等待任务列表下面的代码将一个任务放到事件的等待任务列表中。程序清单 L6.2将一个任务插入到事件的等待任务列表中 pevent-OSEventGrp |= OSMapTblprio 3; pevent-OSEventTblprio 3 |= OSMapTblprio & 0x07;其中,prio是任务的优先级,pevent是指向事件控制块的指针。从程序清单 L6.2可以看出,插入一个任务到等待任务列表中所花的时间是相同的,和表中现有多少个任务无关。从图 F6.2中可以看出该算法的原理:任务优先级的最低3位决定了该任务在相应的.OSEventTbl中的位置,紧接着的3位则决定了该任务优先级在.OSEventTbl中的字节索引。该算法中用到的查找表OSMapTbl(定义在OS_CORE.C中)一般在ROM中实现。表T6.1 OSMapTblIndexBit Mask (Binary)000000001100000010200000100300001000400010000500100000601000000710000000从等待任务列表中删除一个任务的算法则正好相反,如程序清单 L6.3所示。程序清单 L6.3 从等待任务列表中删除一个任务if (pevent-OSEventTblprio 3 &= OSMapTblprio & 0x07) = 0) pevent-OSEventGrp &= OSMapTblprio 3;该代码清除了任务在.OSEventTbl中的相应位,并且,如果其所在的组中不再有处于等待该事件的任务时(即.OSEventTblprio3为0),将.OSEventGrp中的相应位也清除了。和上面的由任务优先级确定该任务在等待表中的位置的算法类似,从等待任务列表中查找处于等待状态的最高优先级任务的算法,也不是从.OSEventTbl0开始逐个查询,而是采用了查找另一个表OSUnMapTbl256(见文件OS_CORE.C)。这里,用于索引的8位分别代表对应的8组中有任务处于等待状态,其中的最低位具有最高的优先级。用这个值索引,首先得到最高优先级任务所在的组的位置(07之间的一个数)。然后利用.OSEventTbl中对应字节再在OSUnMapTbl中查找,就可以得到最高优先级任务在组中的位置(也是07之间的一个数)。这样,最终就可以得到处于等待该事件状态的最高优先级任务了。程序清单 L6.4是该算法的具体实现代码。程序清单 L6.4 在等待任务列表中查找最高优先级的任务 y = OSUnMapTblpevent-OSEventGrp; x = OSUnMapTblpevent-OSEventTbly; prio = (y 3) + x;举例来说,如果.OSEventGrp的值是01101000(二进制),而对应的OSUnMapTbl.OSEventGrp值为3,说明最高优先级任务所在的组是3。类似地,如果.OSEventTbl3的值是11100100(二
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号