ImageVerifierCode 换一换
格式:DOCX , 页数:53 ,大小:289.18KB ,
资源ID:25363260      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/25363260.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(第6章任务之间的通讯与同步.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

第6章任务之间的通讯与同步.docx

1、第6章任务之间的通讯与同步第6章 任务之间的通讯与同步 6.0 事件控制块ECB 6.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 无等待地请求一个信号量, OSSemAccep

2、t() 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 等待一个消息队列中

3、的消息,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

4、_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

5、介绍了任务和中断服务子程序之间是如何进行通讯的。一个任务或者中断服务子程序可以通过事件控制块ECB(Event Control Blocks)来向另外的任务发信号F6.1A(1)。这里,所有的信号都被看成是事件(Event)。这也说明为什么上面把用于通讯的数据结构叫做事件控制块。一个任务还可以等待另一个任务或中断服务子程序给它发送信号F6.1A(2)。这里要注意的是,只有任务可以等待事件发生,中断服务子程序是不能这样做的。对于处于等待状态的任务,还可以给它指定一个最长等待时间,以此来防止因为等待的事件没有发生而无限期地等下去。多个任务可以同时等待同一个事件的发生F6.1B。在这种情况下,当该事

6、件发生后,所有等待该事件的任务中,优先级最高的任务得到了该事件并进入就绪状态,准备执行。上面讲到的事件,可以是信号量、邮箱或者消息队列等。当事件控制块是一个信号量时,任务可以等待它,也可以给它发送消息。图 6.1 事件控制块的使用6.1 事件控制块ECBC/OS-II通过uCOS_II.H 中定义的OS_EVENT数据结构来维护一个事件控制块的所有信息程序清单L6.1,也就是本章开篇讲到的事件控制块ECB。该结构中除了包含了事件本身的定义,如用于信号量的计数器,用于指向邮箱的指针,以及指向消息队列的指针数组等,还定义了等待该事件的所有任务的列表。程序清单 L6.1是该数据结构的定义。程序清单

7、L6.1 ECB数据结构typedef struct void *OSEventPtr; /* 指向消息或者消息队列的指针 */ INT8U OSEventTblOS_EVENT_TBL_SIZE; /* 等待任务列表 */ INT16U OSEventCnt; /* 计数器(当事件是信号量时) */ INT8U OSEventType; /* 时间类型 */ INT8U OSEventGrp; /* 等待任务所在的组 */ OS_EVENT;.OSEventPtr指针,只有在所定义的事件是邮箱或者消息队列时才使用。当所定义的事件是邮箱时,它指向一个消息,而当所定义的事件是消息队列时,它指向一

8、个数据结构,详见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)中的一种。用户要根据该域的具体值来调用相应的系

9、统函数,以保证对其进行的操作的正确性。每个等待事件发生的任务都被加入到该事件事件控制块中的等待任务列表中,该列表包括.OSEventGrp和.OSEventTbl两个域。变量前面的.说明该变量是数据结构的一个域。在这里,所有的任务的优先级被分成8组(每组8个优先级),分别对应.OSEventGrp中的8位。当某组中有任务处于等待该事件的状态时,.OSEventGrp中对应的位就被置位。相应地,该任务在.OSEventTbl中的对应位也被置位。.OSEventTbl数组的大小由系统中任务的最低优先级决定,这个值由uCOS_II.H中的OS_LOWEST_PRIO常数定义。这样,在任务优先级比较少

10、的情况下,减少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时,.OSEven

11、tGrp中的第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-OSEventTb

12、lprio 3 |= OSMapTblprio & 0x07;其中,prio是任务的优先级,pevent是指向事件控制块的指针。从程序清单 L6.2可以看出,插入一个任务到等待任务列表中所花的时间是相同的,和表中现有多少个任务无关。从图 F6.2中可以看出该算法的原理:任务优先级的最低3位决定了该任务在相应的.OSEventTbl中的位置,紧接着的3位则决定了该任务优先级在.OSEventTbl中的字节索引。该算法中用到的查找表OSMapTbl(定义在OS_CORE.C中)一般在ROM中实现。表T6.1 OSMapTblIndexBit Mask (Binary)000000001100000

13、010200000100300001000400010000500100000601000000710000000从等待任务列表中删除一个任务的算法则正好相反,如程序清单 L6.3所示。程序清单 L6.3 从等待任务列表中删除一个任务if (pevent-OSEventTblprio 3 &= OSMapTblprio & 0x07) = 0) pevent-OSEventGrp &= OSMapTblprio 3;该代码清除了任务在.OSEventTbl中的相应位,并且,如果其所在的组中不再有处于等待该事件的任务时(即.OSEventTblprio3为0),将.OSEventGrp中的相应位

14、也清除了。和上面的由任务优先级确定该任务在等待表中的位置的算法类似,从等待任务列表中查找处于等待状态的最高优先级任务的算法,也不是从.OSEventTbl0开始逐个查询,而是采用了查找另一个表OSUnMapTbl256(见文件OS_CORE.C)。这里,用于索引的8位分别代表对应的8组中有任务处于等待状态,其中的最低位具有最高的优先级。用这个值索引,首先得到最高优先级任务所在的组的位置(07之间的一个数)。然后利用.OSEventTbl中对应字节再在OSUnMapTbl中查找,就可以得到最高优先级任务在组中的位置(也是07之间的一个数)。这样,最终就可以得到处于等待该事件状态的最高优先级任务了

15、。程序清单 L6.4是该算法的具体实现代码。程序清单 L6.4 在等待任务列表中查找最高优先级的任务 y = OSUnMapTblpevent-OSEventGrp; x = OSUnMapTblpevent-OSEventTbly; prio = (y OSEventGrp = 0x00; for (i = 0; i OSEventTbli = 0x00; 6.3 使一个任务进入就绪态,OSEventTaskRdy()程序清单 L6.6是函数OSEventTaskRdy()的源代码。当发生了某个事件,该事件等待任务列表中的最高优先级任务(Highest Priority Task HPT)要

16、置于就绪态时,该事件对应的OSSemPost(),OSMboxPost(),OSQPost(),和OSQPostFront()函数调用OSEventTaskRdy()实现该操作。换句话说,该函数从等待任务队列中删除HPT任务(Highest Priority Task),并把该任务置于就绪态。图 F6.4给出了OSEventTaskRdy()函数最开始的4个动作。该函数首先计算HPT任务在.OSEventTbl中的字节索引L6.6/F6.4(1),其结果是一个从0到OS_LOWEST_PRIO/8+1之间的数,并利用该索引得到该优先级任务在.OSEventGrp中的位屏蔽码L6.6/F6.4(

17、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()函

18、数对.OSTCBDly域的递减操作,所以OSEventTaskRdy()直接将该域清澈0L6.6(8)。因为该任务不再等待该事件的发生,所以OSEventTaskRdy()函数将其任务控制块中指向事件控制块的指针指向NULLL6.6(9)。如果OSEventTaskRdy()是由OSMboxPost()或者OSQPost()调用的,该函数还要将相应的消息传递给HPT,放在它的任务控制块中L6.6(10)。另外,当OSEventTaskRdy()被调用时,位屏蔽码msk作为参数传递给它。该参数是用于对任务控制块中的位清零的位屏蔽码,和所发生事件的类型相对应L6.6(11)。最后,根据.OSTCB

19、Stat判断该任务是否已处于就绪状态L6.6(12)。如果是, 则将HPT插入到C/OS-II的就绪任务列表中L6.6(13)。注意,HPT任务得到该事件后不一定进入就绪状态,也许该任务已经由于其它原因挂起了。见4.07节,挂起一个任务,OSTaskSuspend(),和4.08节,恢复一个任务,OSTaskResume()。另外,.OSEventTaskRdy()函数要在中断禁止的情况下调用。程序清单 L6.6 使一个任务进入就绪状态void OSEventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) OS_TCB *ptcb; INT8U

20、 x; INT8U y; INT8U bitx; INT8U bity; INT8U prio; y = OSUnMapTblpevent-OSEventGrp; (1) bity = OSMapTbly; (2) x = OSUnMapTblpevent-OSEventTbly; (3) bitx = OSMapTblx; (4) prio = (INT8U)(y OSEventTbly &= bitx) = 0) (6) pevent-OSEventGrp &= bity; ptcb = OSTCBPrioTblprio; (7) ptcb-OSTCBDly = 0; (8) ptcb-O

21、STCBEventPtr = (OS_EVENT *)0; (9)#if (OS_Q_EN & (OS_MAX_QS = 2) | OS_MBOX_EN ptcb-OSTCBMsg = msg; (10)#else msg = msg;#endif ptcb-OSTCBStat &= msk; (11) if (ptcb-OSTCBStat = OS_STAT_RDY) (12) OSRdyGrp |= bity; (13) OSRdyTbly |= bitx; 图 F6.4 使一个任务进入就绪状态Figure 6.46.4 使一个任务进入等待某事件发生状态, OSEventTaskWait(

22、)程序清单 L6.7是OSEventTaskWait()函数的源代码。当某个任务要等待一个事件的发生时,相应事件的OSSemPend(),OSMboxPend()或者OSQPend()函数会调用该函数将当前任务从就绪任务表中删除,并放到相应事件的事件控制块的等待任务表中。程序清单 L6.7 使一个任务进入等待状态void OSEventTaskWait (OS_EVENT *pevent) OSTCBCur-OSTCBEventPtr = pevent; (1) if (OSRdyTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0) (2) OSRdyG

23、rp &= OSTCBCur-OSTCBBitY; pevent-OSEventTblOSTCBCur-OSTCBY |= OSTCBCur-OSTCBBitX; (3) pevent-OSEventGrp |= OSTCBCur-OSTCBBitY;在该函数中,首先将指向事件控制块的指针放到任务的任务控制块中 L6.7(1),接着将任务从就绪任务表中删除L6.7(2),并把该任务放到事件控制块的等待任务表中L6.7(3)。6.5 由于等待超时而将任务置为就绪态, OSEventTO()程序清单 L6.8是OSEventTO()函数的源代码。当在预先指定的时间内任务等待的事件没有发生时,OST

24、imeTick()函数会因为等待超时而将任务的状态置为就绪。在这种情况下,事件的OSSemPend(),OSMboxPend()或者OSQPend()函数会调用OSEventTO()来完成这项工作。该函数负责从事件控制块中的等待任务列表里将任务删除L6.8(1),并把它置成就绪状态L6.8(2)。最后,从任务控制块中将指向事件控制块的指针删除L6.8(3)。用户应当注意,调用OSEventTO()也应当先关中断。程序清单 L6.8 因为等待超时将任务置为就绪状态void OSEventTO (OS_EVENT *pevent) if (pevent-OSEventTblOSTCBCur-OST

25、CBY &= OSTCBCur-OSTCBBitX) = 0) (1) pevent-OSEventGrp &= OSTCBCur-OSTCBBitY; OSTCBCur-OSTCBStat = OS_STAT_RDY; (2) OSTCBCur-OSTCBEventPtr = (OS_EVENT *)0; (3)6.6 信号量C/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样C/OS-II才能支持信号量。在使用一个信

26、号量之前,首先要建立该信号量,也即调用OSSemCreate()函数(见下一节),对信号量的初始计数值赋值。该初始值为0到65,535之间的一个数。如果信号量是用来表示一个或者多个事件的发生,那么该信号量的初始值应设为0。如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。C/OS-II提供了5个对信号量进行操作的函数。它们是:OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和

27、OSSemQuery()函数。图 F6.5说明了任务、中断服务子程序和信号量之间的关系。图中用钥匙或者旗帜的符号来表示信号量:如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。符号旁边的数字N代表可用资源数。对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。这时的数字N代表事件已经发生的次数。从图 F6.5中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而OSSemPend()和OSSemQuery()函数只能有任务程序调用。图 F6.5 任务、中断服务子程序和信号量之间的关系Figure 6.56.6.1 建立一个信号量, OSSemCreate()程序清单 L6.9是OSSemCreate()函数的源代码。首先,它从空闲任务控制块链表中得到一个事件控制块L6.9(1),并对空闲事件控制链表的指针进行适当的调整,使它指向下一个空闲的事件控制块L6.9(2)

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1