复习题
一、概述
1、μC/OS-II嵌入式操作系统的主要组成部分。
2、μC/OS-II嵌入式操作系统的主要特点。
1).资源占用最小化 微内核结构
模块化(系统可裁减 ) 2).实时性 3).事件驱动
优先级任务调度和抢占式调度 切换时间和中断延迟时间确定 4).非通用性,不易垄断
3、μC/OS-II的裁剪:修改OS_CFG.h文件。
OS_CFG.H是配置文件, μC/OS-II是依靠编译时的条件编译来实现可裁剪性的。即把用户可以裁剪的代码段放在#if 和 #endif预编译指令之间,在编译时根据#if 后面的常数来决定该段代码是否编译到目标代码中。而#if 后面的常数一般就是在OS_CFG.H中定义的。
二、基本任务管理
1、任务的基本构成:任务控制块、任务堆栈、任务函数
2、任务控制块(Task Control Block,TCB)就相当于是一个任务的身份证,任何已经创建的任务都有唯一的任务控制块。了解任务控制块TCB的主要字段的含义和作用。
任务控制块用来记录任务的堆栈指针、任务状态、优先级等一些与任务管理有关的属性 3、任务堆栈主要用于在任务切换是保存现场和恢复现场,所以每个任务都必须有它的专用任务堆栈。即使是基于同一任务函数创建的多个任务也应当有它们各自专用的任务堆栈。
注意:掌握任务创建函数的使用方法。
INT8U OSTaskCreate (
void (*task)(void *pd),//指向任务的指针 void *pdata, //传递给任务的参数
OS_STK *ptos, //指向任务堆栈栈顶的指针 INT8U prio //任务的优先级 )
例如:根据函数函数MyTask和其任务堆栈MyTaskStk定义一个优先级为5的任务:
OSTaskCreate(MyTask, 0, &MyTaskStk[TaskStkSize-1], 5);
3、注意任务函数的框架。如何向任务函数传递参数(实验二)。
void TaskSendByUart(void *pdata) { Baud = *(INT16U*) pdata; while(1) {} }
4、任务状态及其状态转换:哪些转换是可能的,哪些转换是不可能的?
5、在μC/OS-II中,不同的任务具有不同优先级。注意理解优先级含义。
6、基于μC/OS-II应用程序在调用其他系统函数之前,必需先调用OSInit()对包括全局变量和数据结构的运行环境进行初始化。
7、在基于μC/OS-II的应用程序设计中,创建用户任务后,必需调用OSStart() 启动μC/OS-II操作系统,把控制权交给操作系统内核,开始任务调度。
8、一个正在运行任务如要挂起任务自身,则调用OSTaskSuspend(OS_PRIO_SELF) 9、在μC/OS-II中,恢复被挂起任务函数的函数原型是OSTaskResume(INT8U prio) 请问能否通过任务的挂起和恢复实现两个任务的交替执行?(参照相关示例)
void MyTask(void *pdata) {
while(1) { printf(\ Beep(1950, 20); n++; //通过空循环进行延时 if(n>=10) {
printf(\
n = 0; OSTaskSuspend(OS_PRIO_SELF); } } }
OSTaskResume(5) 恢复优先级为5的任务MyTask,MyTask进入就绪状态,由于其优先级高过 当前任务YourTask,所以通过任务调度进入运行状态 void YourTask(void *pdata) { while(1) {
printf(\ Beep(4000, 20); m++;
//通过空循环进行延时 if(m>=10) {
printf(\ m = 0;
OSTaskResume(5); } }
10、正在运行的任务如果需要删除自身,则需要调用OSTaskDel(OS_PRIO_SELF)。 OS_PRIO_SELF为常数,用这个参数就是对本任务进行操作。
11、在单处理器的多任务系统中,任务什么时候占用处理器和能占用多长时间,取决于:任务自身状态、优先级和任务调度策略 二、任务之间的同步
1、在任务同步时,生产者(控制任务)和消费者(被控任务)的优先级一般如何设置?谁负责发送信号量,谁申请信号量?信号量计数器的初始值如何设置?通过示例总结理解。
在通过信号量实现两个任务单向同步时,为了达到较好的同步效果,一般将发送信号量任务设置较低优先级,将接收信号量任务设置较高优先级。
2、如果希望实现多个任务同步一个任务,一般采用信号量集(事件标志组)。通过示例了解。 3、如果希望一个任务同步多个任务,则一般采用消息广播(或者多个信号量)。通过示例理解。
4、当利用信号量用于实现两个任务对一个共享资源共享访问时,则创建该信号量时的信号量计数器OSEventCnt的初始值应设置为1。
Sem = OSSemCreate(1);
写出各个访问共享资源任务的任务函数框架。
void MyTask(void *pdata) { while(1) {
OSSemPend(sem,0,&err); OSSemPost(sem); } }
void YourTask(void *pdata) { while(1) {
OSSemPend(sem,0,&err); OSSemPost(sem); } }
5、分析产生死锁的原因以及解决死锁的策略。
原因:死锁是指两个任务以上无限期地互相等待其他任务控制着的资源。
解决策略:每个必须先得到全部需要的资源再做下一步的工作,而且用同样的顺序去申请多个资源;资源利用完后使用相反的顺序释放资源;在申请信号量时定义等待超时,如果在给定的时限内没有申请成功,则释放原来占用的信号量(资源)。:
每个必须先得到全部需要的资源再做下一步的工作,而且用同样的顺序去申请多个资源;资源利用完后使用相反的顺序释放资源;
在申请信号量时定义等待超时,如果在给定的时限内没有申请成功,则释放原来占用的信号量(资源)。
6、任何任务创建后,在它的生命周期中,其优先级一定不会发生改变吗?
占用互斥信号量的任务在执行过程中优先级可能发生改变。(请问在什么时候可能发生改变),通过实验示例加以理解。 当一个优先级较低的任务已经申请到信号量,而另一个优先级较高的任务也申请该信号量时,优先级较低的任务的优先级将发生改变。
7、请说明信号量的应用情形,分析在不同的应用情况下(行为同步、资源互斥访问),创建信号量时设置的信号量计数器初始值有什么不同。
理解实验中所有与任务之间同步(行为同步、资源访问同步)有关的代码。 行为同步:信号量计数器初始值为0
资源互斥访问:信号量计数器初始值为可访问的资源数量。
8、什么是优先级反转,并说明解决优先级反转的解决方法。(上课示例、实验五)
在可剥夺型内核中,当任务以独占方式使用共享资源时,会出现低优先级任务先于高优先级任务而被运行的现象,这种现象叫做任务优先级反转。
解决问题的办法之一,是使获得信号量任务的优先级在使用共享资源期间暂时提升它的优先级,以使该任务不被其他的任务所打断,从而能尽快使用完共享资源并释放资源使用权(信号量),然后在释放了资源使用权(信号量)之后再恢复该任务原来的优先级别。
9、设有三个任务TaskA、TaskB、TaskC,它们共享一个缓冲区S。TaskA负责从输入设备读信息,每读一纪录后,把它存放在缓冲区S;TaskB负责对缓冲区中的纪录进行加工;TaskC把加工后的纪录打印输出。读入的纪录加工输出后,缓冲区中只可存放下一个纪录。请给出解决上述问题的应用程序的示意性代码(除与任务之间同步、通信有关的代码外可以用伪码)。
sem1 = OSSemCreate(1); sem2 = OSSemCreate(0); sem3 = OSSemCreate(0); void TaskA(void *pdata) {
while(1) {
OSSemPend(sem1,0,&err); //从输入设备读信息 OSSemPost(sem2); } }
void TaskB(void *pdata) {
while(1) {
OSSemPend(sem2,0,&err); //对缓冲区的中的记录进行加工 OSSemPost(sem3); } }
void TaskC(void *pdata) {
while(1) {
OSSemPend(sem3,0,&err); //把加工后的记录打印输出 OSSemPost(sem1); } }
10、理解上课示例和实验所有与同步、死锁、优先级反转有关代码。 三、任务之间的数据通信