《嵌入式实时操作系统ucosII实验2.doc》由会员分享,可在线阅读,更多相关《嵌入式实时操作系统ucosII实验2.doc(14页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、嵌入式实时操作系统实验报告 任务间通信机制的建立 系 别 计算机与电子系 专业班级 电子0901班 学生姓名 高傲 指导教师 黄向宇 提交日期 2012 年 4 月 1 日 一、实验目的二掌握在基于嵌入式实时操作系统C/OS-II的应用中,任务使用信号量的一般原理。掌握在基于优先级的可抢占嵌入式实时操作系统的应用中,出现优先级反转现象的原理及解决优先级反转的策略优先级继承的原理。二、实验内容1.建立并熟悉Borland C 编译及调试环境。2.使用课本配套光盘中第五章的例程运行(例5-4,例5-5,例5-6),观察运行结果,掌握信号量的基本原理及使用方法,理解出现优先级反转现象的根本原因并提出
2、解决方案。3.试编写一个应用程序,采用计数器型信号量(初值为2),有3个用户任务需要此信号量,它们轮流使用此信号量,在同一时刻只有两个任务能使用信号量,当其中一个任务获得信号量时向屏幕打印“TASK N get the signal”。观察程序运行结果并记录。4. 试编写一个应用程序实现例5-7的内容,即用优先级继承的方法解决优先级反转的问题,观察程序运行结果并记录。5.在例5-8基础上修改程序增加一个任务HerTask,它和YouTask一样从邮箱Str_Box里取消息并打印出来,打印信息中增加任务标识,即由哪个任务打印的;MyTask发送消息改为当Times为5的倍数时才发送,HerTas
3、k接收消息采用无等待方式,如果邮箱为空,则输出“The mailbox is empty”, 观察程序运行结果并记录。三、实验原理1. 信号量C/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样C/OS-II才能支持信号量。在使用一个信号量之前,首先要建立该信号量,也即调用OSSemCreate()函数(见下一节),对信号量的初始计数值赋值。该初始值为0到65,535之间的一个数。如果信号量是用来表示一个或者多个事件的发
4、生,那么该信号量的初始值应设为0。如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。C/OS-II提供了5个对信号量进行操作的函数。它们是:OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()函数。图 F6.5说明了任务、中断服务子程序和信号量之间的关系。图中用钥匙或者旗帜的符号来表示信号量:如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。符号旁
5、边的数字N代表可用资源数。对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。这时的数字N代表事件已经发生的次数。从图 F6.5中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而OSSemPend()和OSSemQuery()函数只能有任务程序调用。2. 优先级反转在本实验中,要体现嵌入式实时内核的优先级抢占调度的策略,并显现由于共享资源的互斥访问而出现的优先级反转现象。优先级反转发生在有多个任务需要使用共享资源的情况下,可能会出现高优先级任务被低优先级任务阻塞,并等待低优先级任务执行的现象。高优先级任务需要等待低优先级任务释放资源,而低优先级任
6、务又正在等待中等优先级任务,这种现象就被称为优先级反转。两个任务都试图访问共享资源是出现优先级反转最通常的情况。为了保证一致性,这种访问应该是顺序进行的。如果高优先级任务首先访问共享资源,则会保持共享资源访问的合适的任务优先级顺序;但如果是低优先级任务首先获得共享资源的访问,然后高优先级任务请求对共享资源的访问,则高优先级任务被阻塞,直到低优先级任务完成对共享资源的访问。3. 优先级继承优先级继承的主要思想是:当高优先级任务因申请某共享资源失败被阻塞时,把当前拥有该资源的、且优先级较低的任务的优先级提升,提升的高度等于这个高优先级任务的优先级。在C/OS-II中,在创建管理共享资源的互斥信号量
7、时,可以指定一个PIP(优先级继承优先级),之后可以把拥有共享资源的任务优先级提升到这个高度。具体过程如下:1. 当任务A申请共享资源S时,首先判断是否有别的任务正在占用资源S,若无,则任务A获得资源S并继续执行;2. 如果任务A 申请共享资源S 时任务B 正在使用该资源,则任务A 被挂起,等待任务B 释放该资源;同时判断任务B 的优先级是否低于任务A 的,若高于任务A,则维持任务B的优先级不变;3. 如果任务B的优先级低于任务A的,则提升任务B的优先级到PIP,当任务B释放资源后,再恢复其原来的优先级。4. 建立一个信号量, OSSemCreate()程序清单 L6.9是OSSemCreat
8、e()函数的源代码。首先,它从空闲任务控制块链表中得到一个事件控制块L6.9(1),并对空闲事件控制链表的指针进行适当的调整,使它指向下一个空闲的事件控制块L6.9(2)。如果这时有任务控制块可用L6.9(3),就将该任务控制块的事件类型设置成信号量OS_EVENT_TYPE_SEML6.9(4)。其它的信号量操作函数OSSem?()通过检查该域来保证所操作的任务控制块类型的正确。例如,这可以防止调用OSSemPost()函数对一个用作邮箱的任务控制块进行操作6.06节,邮箱。接着,用信号量的初始值对任务控制块进行初始化L6.9(5),并调用OSEventWaitListInit()函数对事件
9、控制任务控制块的等待任务列表进行初始化见6.01节,初始化一个任务控制块,OSEventWaitListInit()L6.9(6)。因为信号量正在被初始化,所以这时没有任何任务等待该信号量。最后,OSSemCreate()返回给调用函数一个指向任务控制块的指针。以后对信号量的所有操作,如OSSemPend(), OSSemPost(), OSSemAccept()和OSSemQuery()都是通过该指针完成的。因此,这个指针实际上就是该信号量的句柄。如果系统中没有可用的任务控制块,OSSemCreate()将返回一个NULL指针。值得注意的是,在C/OS-II中,信号量一旦建立就不能删除了,因
10、此也就不可能将一个已分配的任务控制块再放回到空闲ECB链表中。如果有任务正在等待某个信号量,或者某任务的运行依赖于某信号量的出现时,删除该任务是很危险的。程序清单 L6.9 建立一个信号量OS_EVENT *OSSemCreate (INT16U cnt) OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList;(1) if (OSEventFreeList != (OS_EVENT *)0) (2) OSEventFreeList = (OS_EVENT *)OSEventFreeList-OSEventPtr; OS_
11、EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) (3) pevent-OSEventType = OS_EVENT_TYPE_SEM;(4) pevent-OSEventCnt = cnt;(5) OSEventWaitListInit(pevent);(6) return (pevent);(7)5. 邮箱邮箱是C/OS-II中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量。该指针指向一个包含了特定“消息”的数据结构。为了在C/OS-II中使用邮箱,必须将OS_CFG.H中的OS_MBOX_EN常数置为1。使用邮
12、箱之前,必须先建立该邮箱。该操作可以通过调用OSMboxCreate()函数来完成(见下节),并且要指定指针的初始值。一般情况下,这个初始值是NULL,但也可以初始化一个邮箱,使其在最开始就包含一条消息。如果使用邮箱的目的是用来通知一个事件的发生(发送一条消息),那么就要初始化该邮箱为NULL,因为在开始时,事件还没有发生。如果用户用邮箱来共享某些资源,那么就要初始化该邮箱为一个非NULL的指针。在这种情况下,邮箱被当成一个二值信号量使用。C/OS-II提供了5种对邮箱的操作:OSMboxCreate(),OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSM
13、boxQuery()函数。图 F6.6描述了任务、中断服务子程序和邮箱之间的关系,这里用符号“I”表示邮箱。邮箱包含的内容是一个指向一条消息的指针。一个邮箱只能包含一个这样的指针(邮箱为满时),或者一个指向NULL的指针(邮箱为空时)。从图 F6.6可以看出,任务或者中断服务子程序可以调用函数OSMboxPost(),但是只有任务可以调用函数OSMboxPend()和OSMboxQuery()。建立一个邮箱,OSMboxCreate()程序清单 L6.14是OSMboxCreate()函数的源代码,基本上和函数OSSemCreate()相似。不同之处在于事件控制块的类型被设置成OS_EVENT
14、_TYPE_MBOXL6.14(1),以及使用.OSEventPtr域来容纳消息指针,而不是使用.OSEventCnt域L6.14(2)。OSMboxCreate()函数的返回值是一个指向事件控制块的指针L6.14(3)。这个指针在调用函数OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSMboxQuery()时使用。因此,该指针可以看作是对应邮箱的句柄。值得注意的是,如果系统中已经没有事件控制块可用,函数OSMboxCreate()将返回一个NULL指针。邮箱一旦建立,是不能被删除的。比如,如果有任务正在等待一个邮箱的信息,这时删除该邮箱,将有可能产生灾难
15、性的后果。程序清单 L6.14 建立一个邮箱OS_EVENT *OSMboxCreate (void *msg) OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) OSEventFreeList = (OS_EVENT *)OSEventFreeList-OSEventPtr; OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) pevent-OSEventType = OS_EVENT_TYP
16、E_MBOX; (1) pevent-OSEventPtr = msg; (2) OSEventWaitListInit(pevent); return (pevent); (3)等待一个邮箱中的消息,OSMboxPend()程序清单 L6.15是OSMboxPend()函数的源代码。同样,它和OSSemPend()也很相似,因此,在这里只讲述其中的不同之处。OSMboxPend()首先检查该事件控制块是由OSMboxCreate()函数建立的L6.15(1)。当.OSEventPtr域是一个非NULL的指针时,说明该邮箱中有可用的消息L6.15(2)。这种情况下,OSMboxPend()函数
17、将该域的值复制到局部变量msg中,然后将.OSEventPtr置为NULLL6.15(3)。这正是我们所期望的,也是执行OSMboxPend()函数最快的路径。如果此时邮箱中没有消息是可用的(.OSEventPtr域是NULL指针),OSMboxPend()函数检查它的调用者是否是中断服务子程序L6.15(4)。象OSSemPend()函数一样,不能在中断服务子程序中调用OSMboxPend(),因为中断服务子程序是不能等待的。这里的代码同样是为了以防万一。但是,如果邮箱中有可用的消息,即使从中断服务子程序中调用OSMboxPend()函数,也一样是成功的。如果邮箱中没有可用的消息,OSMbo
18、xPend()的调用任务就被挂起,直到邮箱中有了消息或者等待超时L6.15(5)。当有其它的任务向该邮箱发送了消息后(或者等待时间超时),这时,该任务再一次成为最高优先级任务,OSSched()返回。这时,OSMboxPend()函数要检查是否有消息被放到该任务的任务控制块中L6.15(6)。如果有,那么该次函数调用成功,对应的消息被返回到调用函数。程序清单 L6.15 等待一个邮箱中的消息void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) void *msg; OS_ENTER_CRITICAL(); if (pev
19、ent-OSEventType != OS_EVENT_TYPE_MBOX) (1) OS_EXIT_CRITICAL(); *err = OS_ERR_EVENT_TYPE; return (void *)0); msg = pevent-OSEventPtr; if (msg != (void *)0) (2) pevent-OSEventPtr = (void *)0; (3) OS_EXIT_CRITICAL(); *err = OS_NO_ERR; else if (OSIntNesting 0) (4) OS_EXIT_CRITICAL(); *err = OS_ERR_PEND_
20、ISR; else OSTCBCur-OSTCBStat |= OS_STAT_MBOX; (5) OSTCBCur-OSTCBDly = timeout; OSEventTaskWait(pevent); OS_EXIT_CRITICAL(); OSSched(); OS_ENTER_CRITICAL(); if (msg = OSTCBCur-OSTCBMsg) != (void *)0) (6) OSTCBCur-OSTCBMsg = (void *)0; OSTCBCur-OSTCBStat = OS_STAT_RDY; OSTCBCur-OSTCBEventPtr = (OS_EVE
21、NT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; else if (OSTCBCur-OSTCBStat & OS_STAT_MBOX) (7) OSEventTO(pevent); (8) OS_EXIT_CRITICAL(); msg = (void *)0; (9) *err = OS_TIMEOUT; else msg = pevent-OSEventPtr; (10) pevent-OSEventPtr = (void *)0; (11) OSTCBCur-OSTCBEventPtr = (OS_EVENT *)0; (12) OS_EXIT
22、_CRITICAL(); *err = OS_NO_ERR; return (msg);无等待地从邮箱中得到一个消息, OSMboxAccept()应用程序也可以以无等待的方式从邮箱中得到消息。这可以通过程序清单 L6.17中的OSMboxAccept()函数来实现。OSMboxAccept()函数开始也是检查事件控制块是否是由OSMboxCreate()函数建立的 L6.17(1)。接着,它得到邮箱中的当前内容L6.17(2),并判断是否有消息是可用的L6.17(3)。如果邮箱中有消息,就把邮箱清空L6.17(4),而邮箱中原来指向消息的指针被返回给OSMboxAccept()的调用函数L6
23、.17(5)。OSMboxAccept()函数的调用函数必须检查该返回值是否为NULL。如果该值是NULL,说明邮箱是空的,没有可用的消息。如果该值是非NULL值,说明邮箱中有消息可用,而且该调用函数已经得到了该消息。中断服务子程序在试图得到一个消息时,应该使用OSMboxAccept()函数,而不能使用OSMboxPend()函数。OSMboxAccept()函数的另一个用途是,用户可以用它来清空一个邮箱中现有的内容。程序清单 L6.17 无等待地从邮箱中得到消息void *OSMboxAccept (OS_EVENT *pevent) void *msg; OS_ENTER_CRITICA
24、L(); if (pevent-OSEventType != OS_EVENT_TYPE_MBOX) (1) OS_EXIT_CRITICAL(); return (void *)0); msg = pevent-OSEventPtr; (2) if (msg != (void *)0) (3) pevent-OSEventPtr = (void *)0; (4) OS_EXIT_CRITICAL(); return (msg); (5)四、实验步骤1. 准备实验环境先在C盘上建一个名称为bc31的目录,然后到互联网上下载一个Borland C+3.1并安装到目录bc31中(因为书中的代码是用
25、Borland C+3.1编译的),接着再把实验程序文件夹Software复制到C盘上。2. 打开实验例程1)运行C:SOFTWARESOFTWAREuCOS-II例4-4Bc31TEST.exe, 观察运行结果;运行结果如下:例题4-4运行结果: 例题4-5运行结果:例题4-6运行结果:2)分析整个实验文件目录结构及实验参考程序。实验参考程序分析:a.例题4-4:ucos-II进行初始化和配置后,由于MyTask任务的优先级高,则先运行MyTask,MyTask是对信号量进行操作的一个任务,先向共享资源Fun_Semp请求信号量,显示字符MyTask,在调用一次Fun函数,再发送信号量给Fu
26、n_Semp。而后优先级低的YouTask执行,也是先向共享资源Fun_Semp请求信号量,显示字符YouTask,在调用一次Fun函数,再发送信号量给Fun_Semp。这样让MyTask和YouTask能交替共享资源Fun_Semp,由于MyTask延时只有1s,所以YouTask每执行一次,MyTask执行2次。b.例题4-5: ucos-II进行初始化和配置后,先执行优先级高的MyTask,先进行信号量的请求,但由于YouTask未对信号量进行释放,所以不显示MyTask而显示YouTask,当YouTask执行6次后,释放信号量,此时MyTask向共享资源请求Fun_Semp请求信号量
27、成功,显示MyTask,并调用一次Fun函数,而后在运行优先级低的YouTask。c.例题4-6:ucos-II进行初始化和配置后,任务MyTask和HerTask都要使用一个共享资源Semp,而用于保护该资源的信号量在同一时间只能有一个任务以独占的方式对该资源进行访问,任务HerTask正在运行,且在t1时刻获得信号量并开始访问共享资源Semp,在此过程中,任务YouTask等待的事件也来了,由于任务YouTask的优先级高于HerTask,所以任务YouTask剥夺了任务HerTask的CPU使用权,任务HerTask只好等待,这样任务MyTask只有当任务YouTask运行结束,并使任务
28、HerTask继续运行且释放了信号量的时刻,才能获得信号量而得以重新运行。出现优先级反转现象的原因:是因为一个优先级别较低的任务在获得了信号量使用共享资源期间,被较高优先级的任务打断而不能释放信号量,从而使正在等待这个信号量的更高级别的任务因得不到信号量而被迫处于等待状态,这个等待期间,就让优先级别低于它而高于占据信号量的任务的任务先运行了。解决优先级反转现象:使获得信号量的任务的优先级别在使用共享资源期间暂时提升到所有任务最高优先级的高一个级别上,以使该任务不被其他任务所打断,从而能尽快地使用完共享资源而释放信号量,而后在释放信号量之后,再恢复该任务原来的优先级别。3)按照实验内容要求编写程
29、序并编译运行五、实验现象与结果分析实验内容3程序运行结果:实验内容4运行结果:结果分析:采用优先级继承的方法,将HerTask的优先级提升到最高优先级高一个级别上,则MyTask获得信号量时,由于被调整后的任务HerTask优先级高于MyTask,故HerTask运行并释放信号量,而后MyTask获得信号量并运行。实验5运行结果:运行结果分析 :uCOS-II经过初始化和相关设置,MyTask发送消息邮箱,YouTask和HerTask向Str_Box请求消息邮箱,开始请求时消息邮箱为空,故HerTask显示The mailbox is empty,再优先级高的YouTask从消息邮箱取出信息并打印消息,显示YouTask而后优先级低的HerTask从消息邮箱取出信息并打印消息,而后消息邮箱变空,打印消息The mailbox is empty,且MyTask是5的倍数才发消息,如此循环显示下去。