VxWorks实验分解.docx
《VxWorks实验分解.docx》由会员分享,可在线阅读,更多相关《VxWorks实验分解.docx(27页珍藏版)》请在冰点文库上搜索。
VxWorks实验分解
实验一测量程序的执行时间
1实验目的
1.1学习使用Tornado开发环境;
1.2测量程序的执行时间
2实验内容
在Tornado开发环境中,建立一个Downloadable的project。
编写一段小程序,并根据需要选择timex()或timexN()测量这段程序的执行时间。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
实时系统应用程序必须优化执行的时间,编程者应当清楚知道自己编写的每段代码的执行时间。
VxWorks提供了一组调用:
timex()和timexN()可以测量应用程序的执行时间。
对于执行时间非常短的程序,timexN()可以通过重复执行该程序来完成计时。
timex()测量一个程序的单次执行时间,允许向该程序传递最多8个参数。
当执行完成时,timex()显示程序的执行时间和测量误差。
如果被测试程序执行太快,比系统时钟速率还快,测量误差大于50%,测量就没有意义,这时会显示一个警告信息。
对于这种情况,应该使用timexN()测试该程序多次执行的时间。
timex()的原型为:
下面的例子中包含两个子程序。
第一个子程序s1_time()调用timex()测量第二个子程序printit()的执行时间。
printit()重复显示其任务id号和变量i的值,重复次数由宏ITERATIONS指定。
5实验步骤
5.1创建project。
5.2编程(假设编写的源文件为s1_time.c)。
5.3将s1_time.c添加到project中。
5.4编译(如果有错误,则改正)。
5.5下载到VxSim模拟器上运行。
5.6改变ITERATIONS的值为300,400,500,600,700,观察程序执行时间的变化。
5.7减少ITERATIONS的值为180,160,140,120,100,观察程序执行时间和输出信息的变化。
5.8继续减少ITERATIONS的值为80,60,40,20,10,观察程序执行时间和输出信息的变化,将timex()改成timexN(),观察程序执行时间和输出信息。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
6.3附上源程序。
实验二多任务编程
1实验目的
学习创建多个任务。
2实验内容
在新建立的project中,编写一段小程序:
创建10个任务,每个任务输出其任务ID。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
VxWorks允许多任务。
一个多任务环境允许实时应用构造多个独立任务,每个任务单独执行,拥有自己的一套资源。
VxWorks多任务内核wind使用中断驱动,基于优先级的任务调度机制,具有较快的上下文切换时间和较低的中断延迟。
多任务制造一种多个任务同时执行的假象。
事实上,内核通过调度算法让这些任务依次执行。
每个任务拥有自己的上下文,包括CPU环境和系统资源,这些是内核调度该任务运行时所必须的。
在上下文切换时,任务的上下文保存在任务控制块TCB中。
一个任务的上下文包括:
●代码执行点,也就是任务的程序计数器。
●CPU寄存器和浮点数寄存器(如果需要)。
●动态变量和函数调用的堆栈。
●标准输入输出和出错I/O分配。
●一个延时定时器。
●一个时间片定时器。
●内核控制结构。
●信号处理器。
●调试和性能监视值。
4.1任务的创建和激活
函数taskSpawn()创建一个新的任务上下文,包括为程序执行分配和建立人物环境,传递参数。
函数taskSpawn()的参数包括:
任务名,优先级,选项字,堆栈大小,新任务入口,以及传递给该入口的10个参数。
原型为:
下面的例子中包含两个子程序。
第一个子程序s2_tasks()调用taskSpawn()创建TASKS(=10)个任务,每个任务执行task_print()显示其任务id号。
5实验步骤
5.1编程(假设编写的源文件为s2_tasks.c)。
5.2将s2_tasks.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5如果将taskSpawn()调用中的优先级设置改为90+i,观察输出。
5.6如果将taskSpawn()调用中的优先级设置改为90-i,观察输出。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
分析4、5、6步骤中输出变化或不变化的原因。
6.3附上源程序。
实验三信号量
1实验目的
学习使用信号量实现共享资源的保护。
2实验内容
在新建立的project中,创建2个任务,一个任务将全局变量设为1;一个任务将全局变量设为0。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
信号量允许多个任务相互协调其活动。
任务间最直接的通信方式就是共享各种各样的数据结构。
由于VxWorks使用单地址空间,所有任务存在于一个单一的线性地址空间中,共享数据结构也就非常容易实现。
全局变量、各类缓冲、链表和指针都可以被运行在不同任务上下文的代码直接引用。
然而,对于共享的数据,需要保证对其的互斥访问。
VxWorks提供了许多实现共享临界区互斥访问的机制,信号量就是其中一种。
VxWorks内核Wind提供三种类型的信号量用于解决不同类型的问题:
●二进制信号量(binary):
可以用于实现同步和互斥。
●互斥信号量(mutualexclusion):
一种特殊的信号量,适于解决具有内在互斥的问题:
优先级继承、删除安全和递归。
●计数信号量(counting):
适用于保护具有多个数据的资源。
4.1信号量的控制
Wind内核为上述三类信号量提供不同的创建函数:
semBCreate()、semMCreate()和semCCreate(),但提供统一的控制函数:
semDelete()、semTake()、semGive()、semFlush()。
它们的原型分别为:
下面的例子使用二进制信号量。
二进制信号量可以作为资源可用或不可用的标志。
任务使用semTake()取一个信号量,其结果取决于调用时该二进制信号量是否可用。
如果可用,信号量将变得不可用,而任务继续执行。
如果信号量不可用,任务被挂起到任务阻塞队列,直到该信号量可用。
当任务释放一个二进制信号量时要调用semGive(),其结果也要依赖于调用时刻该信号量是否可用。
如果可用,本次释放信号量不起任何作用;如果信号量不可用,而且没有任务在等待该信号量,那么信号量变为可用;如果信号量不可用,并且有一个或多个任务等待该信号量,那么阻塞队列中的第一个任务解除阻塞,而信号量仍不可用。
例中,两个任务(taskOne和taskTwo)竞争修改一个全局变量global的值,任务taskOne将Global修改为1,而任务taskTwo则将其修改为0。
5实验步骤
5.1编程(假设编写的源文件为s3_sem.c)。
5.2将s3_sem.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5如果将22行和34行的两条语句删除,观察输出。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
分析4、5步骤中输出变化或不变化的原因。
6.3附上源程序。
实验四消息队列的使用
1实验目的
1.1学习使用消息队列进行通信。
2实验内容
在新建立的project中,创建2个任务,任务1向任务2发送一条消息,任务2将在控制台上输出。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP。
b)Tornado2.2。
4实验原理
在单CPU中,VxWorks的多任务通信的主要机制是消息队列。
消息队列允许以FIFO或基于优先级方式排队消息,消息的数目可变,消息的长度可变。
任何任务都可以向消息队列发送消息,也可以从消息队列接收消息。
多个任务允许从同一个消息队列收发消息。
但是,两个任务间的双向通信通常需要两个消息队列,各自用于一个方向。
VxWorks消息队列的创建、删除、发送和接收调用如下:
消息队列库允许消息按照FIFO方式排队,但是也有一个例外:
存在两个优先级,优先级最高的消息排在队列的头部。
要创建一个消息队列可以调用msgQCreate()。
任务调用msgQSend()将消息发送到一个消息队列,如果没有任务在等待该队列的消息,那么这条消息增加到该队列的消息缓冲中;如果有任务在等待,那么该消息立即提供给第一个等待的任务。
任务如果需要从一个消息队列接收一条消息,它应该调用msgQReceive()。
如果该消息队列中已有消息可用,那么队列中的第一条消息立即出队,并提交给该任务;如果没有消息可用,那么该任务阻塞,并加入到等待该消息的任务队列中。
等待任务队列可以按两种方式排队:
基于任务优先级或基于FIFO方式,由消息队列创建时指定。
●Timeouts:
函数msgQSend()和msgQReceive()都可以指定一个超时参数,规定任务的等待时间(tick数):
发送消息任务等待队列空间可用,接收消息任务等待消息可用。
●UrgentMessages:
函数msgQSend()可以指定欲发送消息的优先级:
正常MSG_PRI_NORMAL或紧急MSG_PRI_URGENT。
正常优先级的消息加入到消息队列的尾部,而紧急优先级的消息将添加到消息队列的头部。
下面的例子创建两个任务,任务1向任务2发送一个消息,任务2将其显示在控制台上。
5实验步骤
5.1编程(假设编写的源文件为s4_msgq.c)。
5.2将s4_msgq.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5增加另一个消息队列,使得任务2使用该消息队列向任务1发送消息,任务1将消息输出到控制台上。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
6.3附上源程序(修改前和修改后)
实验五时间片轮转调度(Round-Robin)
1实验目的
1.1学习并验证时间片轮转调度。
2实验内容
在新建立的project中,创建3个任务,对这三个任务使用轮转调度。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP。
b)Tornado2.2。
4实验原理
任务调度就是基于某种规则约束,给一个任务集合中的每个任务分配开始和结束时间。
约束一般包括时间约束和资源约束。
在一个时间共享(time-sharing)的操作系统中,系统按照时间片一次轮流执行每个任务,从而制造出多个任务在单个处理器上同时执行的假象。
Wind内核调度默认使用基于优先级抢占式调度,但同时也允许使用轮转调度。
轮转调度的目的是使相同优先级的所有就绪任务共享CPU。
如果不使用轮转调度,当多个相同优先级的任务需要共享处理器时,其中的一个任务可能会霸占处理器,直到该任务完成或因其他原因放弃执行(例如等待一个信号量),从而使得同优先级的其他任务得不到运行的机会。
时间片(timeslicing)是轮转调度在多个相同优先级的任务间公平分配CPU时间的基础。
每个任务执行一段确定的时间(一个时间片);然后另一个任务执行同样大小的一段时间,如此循环下去。
这种分配是相当公平的;在这个优先级相同的任务组中,其他就绪任务没有得到一个时间片之前,不会出现一个任务得到第二个时间片的情形。
在Wind内核中,调用函数kernelTimeSlice()将允许轮转调度,时间片的大小由参数传给它,规定了每个任务一次允许占用CPU的最长时间。
下面的例子创建三个优先级相同的任务,分别向控制台输出他们的任务id号和任务名。
s5_rrsched()调用kernelTimeSlice()允许系统使用轮转调度。
本例中使用的时间片TIMESLICE为1/60秒(函数sysClkRateGet()返回每秒的时钟ticks数)。
在设置了调度时间片后,程序发起三个任务。
注意:
必须保证发起的任务的优先级要比sched任务的优先级(100)低。
例中三个任务的优先级定为101。
另外为了演示时间片轮转的效果,要保证任务具有足够的执行时间,在本例中使用一个循环次数为LONG_TIME的长循环。
5实验步骤
5.1编程(假设编写的源文件为s5_rrsched.c)。
5.2将s5_rrsched.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5增大时间片的长度,观察输出。
5.6取消时间片轮转,观察输出。
5.7增加第四个任务,其优先级为80,它和其他三个任务输出相同的信息,观察运行结果。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
分析4~7步骤的结果。
6.3解答:
在上例中,为什么三个被创建的任务必须比任务sched的优先级低?
6.4附上源程序(修改前和修改后)。
实验六优先级倒转及其解决办法
1实验目的
1.1理解优先级倒转问题
1.2学习使用优先级继承以解决优先级倒转问题
2实验内容
在新建立的project中,创建3个任务,对这三个任务使用基于优先级的抢占式调度。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
当高优先级的任务不得不等待一段不确定的时间,等待低优先级任务完成操作时,就发生优先级倒转。
例如,prioHigh、prioMedium和prioLow三个任务的优先级由高到低排列,prioLow请求一个与二进制信号量相联系的资源,当prioHigh抢占prioLow并需要竞争相同的资源,它将被阻塞。
如果prioHigh阻塞的时间全部用来等待prioLow使用该资源,那么不会存在什么问题,因为资源不会被抢占。
然而,如果这个低优先级的任务不得不被中等优先级的任务prioMedium抢占,由于它不需要使用该资源,这时prioLow仍然占用该资源。
这种情况可能进一步发生,使得prioHigh被迫等待一段不确定的时间。
为避免这种情况,VxWorks引进优先级继承机制。
为使用优先级继承机制,当使用互斥信号量时,VxWorks提供了一个附加的选项SEM_INVERSION_SAFE,它允许使用优先级继承算法,该算法保证占有一个资源的任务,在其运行时,其优先级等于阻塞在该资源上的所有任务的优先级的最高值。
当执行完成,这个任务释放资源,返回正常的优先级。
因此,这个继承了最高优先级的任务,将不会被优先级比它的正常优先级高但又比继承的优先级低的任务抢占。
需要指出的是SEM_INVERSION_SAFE选项必须与SEM_Q_PRIORITY一起使用:
semId=semMCreate(SEM_Q_PRIORITY|SEM_INVERSION_SAFE)
下面的例子说明发生优先级倒转的典型情况:
(1)prioLow任务上锁信号量;
(2)prioLow任务被prioMedium任务抢占而阻塞,后者运行一段较长的时间;
(3)prioHigh任务抢占prioMedium任务,试图上锁被prioLow上锁的信号量。
由于任务prioLow和prioHigh都被阻塞,prioMedium将一直运行直至结束(很长的一段时间)。
这时,prioHigh可能已经错过它的时间限制。
代码如下:
5实验步骤
5.1编程(假设编写的源文件为s7_inversion.c)。
5.2将s7_inversion.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5修改程序,使用优先级继承解决优先级倒转问题。
观察输出。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
6.3附上源程序(修改前和修改后)。
实验七基于优先级的抢占式调度
1实验目的
1.1学习并验证基于优先级的抢占式调度。
2实验内容
在新建立的project中,创建3个任务,对这三个任务使用基于优先级的抢占式调度。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
Wind内核调度默认使用基于优先级抢占式调度。
每个任务有一个优先级,任一时刻,内核保证将CPU分配给处于就绪状态的优先级最高的任务执行。
之所以说这种调度算法是抢占的,是因为,如果在某个时刻,一个优先级比当前正在运行的任务的优先级高的任务变为就绪,那么内核立即保存当前任务的上下文,然后切换到这个最高优先级任务的上下文。
Wind内核有256个优先级(0~255),优先数0对应着最高优先级,优先数255对应着最低优先级。
任务的优先级在其创建时指定,VxWorks也允许任务在执行时调用taskPrioritySet()改变自身的优先级。
函数taskSpawn()用于创建并激活一个新任务。
其原型如下:
当有多个不同优先级的任务时,任务的优先级才有意义。
任务在执行时可以调用下面的函数改变自身的优先级:
下面的例子创建三个优先级各不相同的任务。
5实验步骤
5.1编程(假设编写的源文件为s6_hisched.c)。
5.2将s6_hisched.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
5.5修改程序,使得任务的执行顺序变为:
taskOne,taskTwo,taskThree。
观察输出。
5.6修改程序,使得taskOne具有最高优先级,同时taskTwo也以同样的优先级运行,观察输出结果。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
分析4~6步骤的结果。
6.3附上源程序(修改前和修改后)。
实验八信号
1实验目的
1.1学习使用信号。
2实验内容
在新建立的project中,编写一段信号处理程序,将其与SIGINT相关连,使用kill()发送SIGINT信号并调用信号处理程序。
观察运行结果。
3实验设备及工具
3.1硬件:
a)PC机
3.2软件:
a)PC机操作系统Windows2000或windowsXP
b)Tornado2.2
4实验原理
信号可以用来通知任务处理特定的事件。
当引起一个信号的事件发生时,信号产生(generated)。
当处理事件的任务激活时,信号释放(delivered)。
信号的生命期是从产生到释放之间的时间。
一个已经产生但还没有释放的信号是挂起的(pending)。
信号的生命期可能比较长。
VxWorks允许软件信号功能。
信号将异步地改变任务的控制流。
任何任务都可以向一个特定任务发送信号。
被信号通知的任务立即挂起它当前的执行线程,在下次任务被调度运行的时刻,指定的信号处理程序将获得处理器。
甚至尽管任务处于阻塞状态,其信号处理程序仍可以被调用执行。
信号处理程序是由用户提供并与特定的信号相联系,用于执行当信号发生时必要的处理工作。
信号适用于错误和异常处理,很少用于任务间通信。
Wind内核提供了两种信号接口:
BSD4.3和POSIX信号接口。
POSIX接口提供比BSD4.3接口更强大的标准接口。
应用程序仅能使用其中一个。
VxWorks提供31种不同的信号。
程序可以调用kill()产生一个信号,与中断和硬件异常类似;调用sigaction()将信号与指定的信号处理程序相对应。
当信号处理程序运行时,其他信号被阻塞。
通过调用sigprocmask(),任务可以阻止一些信号的出现,如果当信号产生时被阻塞,它的信号处理程序将在信号解除阻塞时调用。
信号处理程序通常定义形式为:
上面的signalNumber是调用该处理程序的信号编号。
任务可以调用函数sigaction安装信号处理程序:
数据结构structsigaction包含处理程序的信息,sigaction()含有三个参数:
需要捕获的信号编号、指向新的处理数据结构的指针(类型为structsigaction),指向旧的处理数据结构的指针(类型为structsigaction)。
如果程序不需要旧的处理数据结构的指针(*pOact),那么可以传递一个空指针NULL。
当需要把一个信号发送给一个任务时,可以调用kill()函数,第一个参数是任务的id号,第二个参数是欲发送信号。
下面的例子调用kill函数产生一个信号SIGINT,发送给任务sigCatcher。
当sigCatcher接收到该信号输出“sigCatcher:
Igotthissig”并将sigflag置为1。
5实验步骤
5.1编程(假设编写的源文件为s8_signal.c)。
5.2将s8_signal.c添加到project中。
5.3编译(如果有错误,则改正)。
5.4下载到VxSim模拟器上运行,观察输出。
6实验报告要求
6.1写出实验过程。
6.2记录输出结果。
6.3附上源程序。