当前位置:文档之家› 嵌入式实时操作系统实验报告

嵌入式实时操作系统实验报告

嵌入式实时操作系统实验报告任务间通信机制的建立系别计算机与电子系专业班级*****学生姓名******指导教师 ******提交日期 2012 年 4 月 1 日一、实验目的掌握在基于嵌入式实时操作系统μC/OS-II的应用中,任务使用信号量的一般原理。

掌握在基于优先级的可抢占嵌入式实时操作系统的应用中,出现优先级反转现象的原理及解决优先级反转的策略——优先级继承的原理。

二、实验内容1.建立并熟悉Borland C 编译及调试环境。

2.使用课本配套光盘中第五章的例程运行(例5-4,例5-5,例5-6),观察运行结果,掌握信号量的基本原理及使用方法,理解出现优先级反转现象的根本原因并提出解决方案。

3.试编写一个应用程序,采用计数器型信号量(初值为2),有3个用户任务需要此信号量,它们轮流使用此信号量,在同一时刻只有两个任务能使用信号量,当其中一个任务获得信号量时向屏幕打印“TASK N get the signal”。

观察程序运行结果并记录。

4. 试编写一个应用程序实现例5-7的内容,即用优先级继承的方法解决优先级反转的问题,观察程序运行结果并记录。

5.在例5-8基础上修改程序增加一个任务HerTask,它和YouTask一样从邮箱Str_Box里取消息并打印出来,打印信息中增加任务标识,即由哪个任务打印的;MyTask发送消息改为当Times为5的倍数时才发送,HerTask接收消息采用无等待方式,如果邮箱为空,则输出“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之间的一个数。

如果信号量是用来表示一个或者多个事件的发生,那么该信号量的初始值应设为0。

如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。

最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。

µC/OS-II提供了5个对信号量进行操作的函数。

它们是:OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()函数。

图 F6.5说明了任务、中断服务子程序和信号量之间的关系。

图中用钥匙或者旗帜的符号来表示信号量:如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。

符号旁边的数字N代表可用资源数。

对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。

这时的数字N代表事件已经发生的次数。

从图 F6.5中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而OSSemPend()和OSSemQuery()函数只能有任务程序调用。

2. 优先级反转在本实验中,要体现嵌入式实时内核的优先级抢占调度的策略,并显现由于共享资源的互斥访问而出现的优先级反转现象。

优先级反转发生在有多个任务需要使用共享资源的情况下,可能会出现高优先级任务被低优先级任务阻塞,并等待低优先级任务执行的现象。

高优先级任务需要等待低优先级任务释放资源,而低优先级任务又正在等待中等优先级任务,这种现象就被称为优先级反转。

两个任务都试图访问共享资源是出现优先级反转最通常的情况。

为了保证一致性,这种访问应该是顺序进行的。

如果高优先级任务首先访问共享资源,则会保持共享资源访问的合适的任务优先级顺序;但如果是低优先级任务首先获得共享资源的访问,然后高优先级任务请求对共享资源的访问,则高优先级任务被阻塞,直到低优先级任务完成对共享资源的访问。

3. 优先级继承优先级继承的主要思想是:当高优先级任务因申请某共享资源失败被阻塞时,把当前拥有该资源的、且优先级较低的任务的优先级提升,提升的高度等于这个高优先级任务的优先级。

在μC/OS-II中,在创建管理共享资源的互斥信号量时,可以指定一个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是OSSemCreate()函数的源代码。

首先,它从空闲任务控制块链表中得到一个事件控制块[L6.9(1)],并对空闲事件控制链表的指针进行适当的调整,使它指向下一个空闲的事件控制块[L6.9(2)]。

如果这时有任务控制块可用[L6.9(3)],就将该任务控制块的事件类型设置成信号量OS_EVENT_TYPE_SEM[L6.9(4)]。

其它的信号量操作函数OSSem???()通过检查该域来保证所操作的任务控制块类型的正确。

例如,这可以防止调用OSSemPost()函数对一个用作邮箱的任务控制块进行操作[6.06节,邮箱]。

接着,用信号量的初始值对任务控制块进行初始化[L6.9(5)],并调用OSEventWaitListInit()函数对事件控制任务控制块的等待任务列表进行初始化[见6.01节,初始化一个任务控制块,OSEventWaitListInit()][L6.9(6)]。

因为信号量正在被初始化,所以这时没有任何任务等待该信号量。

最后,OSSemCreate()返回给调用函数一个指向任务控制块的指针。

以后对信号量的所有操作,如OSSemPend(), OSSemPost(), OSSemAccept()和OSSemQuery()都是通过该指针完成的。

因此,这个指针实际上就是该信号量的句柄。

如果系统中没有可用的任务控制块,OSSemCreate()将返回一个NULL指针。

值得注意的是,在µC/OS-II中,信号量一旦建立就不能删除了,因此也就不可能将一个已分配的任务控制块再放回到空闲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_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。

使用邮箱之前,必须先建立该邮箱。

该操作可以通过调用OSMboxCreate()函数来完成(见下节),并且要指定指针的初始值。

一般情况下,这个初始值是NULL,但也可以初始化一个邮箱,使其在最开始就包含一条消息。

如果使用邮箱的目的是用来通知一个事件的发生(发送一条消息),那么就要初始化该邮箱为NULL,因为在开始时,事件还没有发生。

如果用户用邮箱来共享某些资源,那么就要初始化该邮箱为一个非NULL的指针。

在这种情况下,邮箱被当成一个二值信号量使用。

µC/OS-II提供了5种对邮箱的操作:OSMboxCreate(),OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSMboxQuery()函数。

图 F6.6描述了任务、中断服务子程序和邮箱之间的关系,这里用符号“I”表示邮箱。

邮箱包含的内容是一个指向一条消息的指针。

一个邮箱只能包含一个这样的指针(邮箱为满时),或者一个指向NULL的指针(邮箱为空时)。

从图 F6.6可以看出,任务或者中断服务子程序可以调用函数OSMboxPost(),但是只有任务可以调用函数OSMboxPend()和OSMboxQuery()。

建立一个邮箱,OSMboxCreate()程序清单 L6.14是OSMboxCreate()函数的源代码,基本上和函数OSSemCreate()相似。

不同之处在于事件控制块的类型被设置成OS_EVENT_TYPE_MBOX[L6.14(1)],以及使用.OSEventPtr域来容纳消息指针,而不是使用.OSEventCnt域[L6.14(2)]。

OSMboxCreate()函数的返回值是一个指向事件控制块的指针[L6.14(3)]。

这个指针在调用函数OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSMboxQuery()时使用。

因此,该指针可以看作是对应邮箱的句柄。

值得注意的是,如果系统中已经没有事件控制块可用,函数OSMboxCreate()将返回一个NULL指针。

邮箱一旦建立,是不能被删除的。

比如,如果有任务正在等待一个邮箱的信息,这时删除该邮箱,将有可能产生灾难性的后果。

程序清单 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_TYPE_MBOX; (1)pevent->OSEventPtr = msg; (2)OSEventWaitListInit(pevent);}return (pevent); (3)}等待一个邮箱中的消息,OSMboxPend()程序清单 L6.15是OSMboxPend()函数的源代码。

相关主题