1、嵌入式操作系统,第3章 VxWorks任务管理,1、 VxWorks下的任务,2、 VxWorks下任务控制及任务编程,3、 VxWorks任务调度,嵌入式操作系统, 重点掌握, VxWorks下任务的特点 VxWorks提供的任务控制函数及应用 VxWorks提供的任务调度策略及应用,嵌入式操作系统,1、 VxWorks下任务的特点,任务运行的地址空间 任务结构 任务的标识 任务的状态及状态转换 任务的上下文切换,嵌入式操作系统, VxWorks中的wind内核为VxWorks提供了一个高性能的实时多任务操作环境, 任务管理、任务创建、任务调度、时钟、中断、内存管理, 在VxWorks中,每
2、个明显独立的程序在运行时称之为任务,嵌入式操作系统,cobble.c, 四个任务, 第一个任务tCosmos模拟一个中断服务程序生成新数据cosmos( ) 第二个任务tSchlep收集数据schlep( ) 第三个任务tCrunch处理数据,完成计算并求出一个结果crunch( ) 第四个任务tMonitor监视结果值,当结果超出安全范围时,向屏幕打印报警信息monitor( ), 子函数nodeAdd( ),nodeScrap( ),嵌入式操作系统,1.1 任务运行的地址空间, VxWorks操作系统采取线性单一实地址空间模式,所有任务都运行在同一地址空间,不区分用户态和核心态,嵌入式操作
3、系统,嵌入式操作系统, VxWorks下任务具有如下特点:, 任务切换时不需要进行虚拟地址空间切换 任务间可以直接共享变量,不需要通过内核在不同的地址空间复制数据 系统调用时不需要在核心态和用户态之间切换,相当于直接的函数调用,嵌入式操作系统, !由于没有访问内存任何约束和保护,因,而对代码质量提出了更高的要求, 当选用VxVMI时,每个任务各自的地址空间需要进行虚拟地址到物理地址的转换,嵌入式操作系统,1.2 任务的结构,data段,数据段,bss段,TCB,代码段,堆栈段,不需要进行用户、内核的区分,嵌入式操作系统,TCB, TCB用来描述一个任务,每一任务都与一个TCB关联, TCB用w
4、indTcb结构体来描述, VxWorks的taskLib库中定义(taskLib.h),嵌入式操作系统, TCB中上下文信息包含的具体内容:, 程序执行点(PC) CPU状态,包括各种处理器特定的寄存器, ,栈 任务的状态 延迟定时器 时间片定时器 I/O操作分配的标准输入/输出,标准错误输出 操作,嵌入式操作系统, ,内核控制结构 信号处理信息 错误信息 调试和性能监视状态 任务变量(可选) 浮点上下文(可选) 可扩展项 (可选),嵌入式操作系统,错误信息, 在VxWorks中有一个全局变量errno来存放系统最近的错误状态值, 每个任务TCB中都记录有一个全局errno副本errosta
5、tus ,属于任务上下文的一部分, ISR也使用独立的errno,但是ISR没有TCB,内核为ISR在中断栈中保存和恢复errno,嵌入式操作系统, errno的值由4个字节表示,2个高字节表示产生错误的模块组件编码,2个低字节表示错误编号, 如0x110001,表示内存不足, VxWorks提供errnoLib库用于获取和设置任务和中断的错误状态值,嵌入式操作系统,任务变量, 当多个任务需要同一全局变量或静态变量提供不同的值时,VxWorks提供任务变量机制来切换全局变量, 任务变量机制允许在任务上下文中定义自己的私有变量,随着上下文切换而切换,嵌入式操作系统,嵌入式操作系统, 每个任务变量
6、允许存放一个4字节的值,typedef struct taskVar /* TASK_VAR */struct taskVar * next;int *address;intvalue; TASK_VAR;, VxWorks提供库taskVarLib库支持任务变量机制,嵌入式操作系统, 当有多个任务变量时,任务变量以单向链表的形式存在,嵌入式操作系统, 任务切换时需要遍历任务变量链表,进行变量值的恢复和保存降低效率, !此机制会降低任务上下文切换的效率,建议编程时谨慎使用,嵌入式操作系统,堆栈, 在任务创建时指定堆栈的大小 TCB记录了位置和大小等栈信息, 任务栈大小的设置必须合理,高地址,p
7、StackEnd,StackSize,pStackBase,TCB,低地址,pTCB,pTaskMem,16bytes,嵌入式操作系统, VxWorks操作系统提供函数checkStack( )来检查任务栈使用情况, checkStack( )显示了单个指定任务或者所有任务的栈使用情况,包括:, ,栈大小(SIZE) 栈当前使用数(CUR) 历史使用峰值(HIGH) 最大可能空余数(MARGIN=SIZE-HIGH), Tornado中的browser也可查看栈的使用情况 !堆栈诊断前提:栈初始化时要用0xee填充,嵌入式操作系统, shell下创建任务时默认堆栈大小(sp命令), #defi
8、ne SHELL_STACK_SIZE 10000, VxWorks支持独立的中断栈,对所有的ISR使用相同的中断栈, 中断栈在系统启动时根据配置参数设置位置、大小和填充。在configAll.h中有缺省定义:,#define ISR_STACK_SIZE,1000,嵌入式操作系统,1.3 任务的标识, VxWorks下标识任务有两种途径:任务名称和任务ID号, 任务名称, 是独一无二的字符串 主机任务以字母u开头 目标机任务以字母t开头, 任务ID号, 长度为4字节,指向TCB, VxWorks提供任务名称和任务ID之间的转换函数,嵌入式操作系统,1.4 任务的状态, 5种基本状态:, ,
9、,执行(RUN) 就绪(READY)任务只需等待cpu 阻塞(PEND)有cpu以外的资源不可用 睡眠(DELAY)任务处于睡眠状态 挂起(SUSPEND)一般用于调试,DELAY+S睡眠+挂起 PEND+S阻塞+挂起状态 PEND+T延时阻塞状态 PEND+T+S延时阻塞+挂起状态 +I继承优先级状态,优先级暂时被提升, 多种组合状态,嵌入式操作系统,任务的状态转换图,任务创建时,处于挂起状态,taskSuspend() taskResume(),挂起,要使刚创建的任务就绪,taskResume() 要激活该任务taskSuspend(),taskSuspend() taskResume()
10、/taskActivate(),阻塞,就绪,semTake()/msgQReceive()semGive()/msgQSend(),抢占 调度,睡眠,taskDelay()使用spawning原语,可以直接延时已到创建并激活一个任务,任务可以在任何状态下被删除,执行,嵌入式操作系统,任务的状态队列,嵌入式操作系统,1.5 任务上下文切换, 上下文切换示意图,TCB(Old),copy of pc,copy of sp,CPU,pc,sp,TCB(New),copy of pc,copy of sp,errorStatus,errno,errorStatus,嵌入式操作系统, 上下文切换分两种情
11、况:同步和异步 同步上下文切换,引起的原因是当前运行的任务执行下列操作:, 进行阻塞、延迟、挂起的调用; 使更高优先级任务就绪而发生优先级抢占 降低自身优先级或者退出;, 异步上下文切换,通常由ISR使更高优先级任务就绪引起。,嵌入式操作系统,1.6 VxWorks的系统任务, 根任务tUsrRoot, 内核执行的第一个任务 初始化VxWorks系统的主要功能,例如, 发起日志任务、异常处理任务、网络任务和tRlogind后台任务, 通常,上述初始化结束之后,根任务终止并删除 用户可以向根任务自由的添加任何必需的初始化代码 对应usrRoot()函数(target/config/all/usr
12、Config.c),嵌入式操作系统, 日志任务:tLogTask, 记录系统信息的任务。它不执行输入/输出操作。, 异常处理任务:tExcTask, 提供VxWorks异常处理包,完成在中断级不能执行的功能 必须具有系统最高的优先级 不能挂起、删除、改变其任务的优先级, 目标代理服务:tWdbTask(INCLUDE_WDB), 当目标代理设置为运行在任务模式时,创建此任务 处理来自Tornado目标服务的请求,以上3种任务都属于VxWorks的基本任务,嵌入式操作系统, 网络任务:tNetTask(INCLUDE_NET_LIB) 后台处理VxWorks网络需要的任务级功能处理, 其他可选组
13、件的任务 tShell(INCLUDE_SHELL) tRlogind(INCLUDE_RLOGIN) tTelnetd(INCLUDE_TELNET) tPortmapd(INCLUDE_RPC),嵌入式操作系统,与Linux比较, 任务控制块的内容,多用户性、任务间的亲属关系、文件打开表、队列信息、 虚拟内存信息、错误状态等, 栈,栈的大小、中断栈, 任务状态,状态的种类、状态间的转换,嵌入式操作系统,2、VxWorks下任务控制及任务编程, ,任务创建和激活 任务删除与任务安全 任务的状态控制 任务信息的获取 任务扩展函数 代码的共享与重入,嵌入式操作系统, VxWorks提供丰富的任务
14、控制功能,包含在taskLib库中, 包括: 任务的创建、删除、状态控制、获取任务信息等等 可以在Tornado IDE提供的shell工具中交互使用这些调用,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统,2.1 任务的创建与激活, VxWorks的TaskLib库中提供多个函数用于创建任务:,调用,taskSpawn(),taskInit(),taskActivate(),描述,创建并激活一个任务,初始化一个新任务,激活一个初始化任务,嵌入式操作系统,taskSpawn()创建并激活一个新任务,int taskSpawn(char *name,/*新任务的任务名*/int
15、priority,/*新任务的优先级*/int options,/*任务选项字*/int stackSize,/*堆栈大小*/FUNCPTR entryPt,/*新任务的入口函数*/int arg1,arg2,arg3,arg4,arg5, /*传递给入口函数*/int arg6,arg7,arg8,arg9,arg10 /*的10参数*/),嵌入式操作系统,TaskSpawn(), 创建新任务的上下文 堆栈、TCB、含有特定参数的入口程序调用的任务环境(入口程序通常是一个普通的程序) 新的任务将在指定的函数入口处执行 激活新任务 堆栈是系统资源,位于系统内存中 其底端是TCB 堆栈使用0xE
16、E填充 任务名要便于记忆,可以是任意长度、任意内容,嵌入式操作系统, taskSpawn中的任务选项参数可以是下表中的选项之一或其组合,如果任务使用任何浮点操作,必须要求使用VX_FP_TASK选项,嵌入式操作系统, 任务的优先级: Wind内核支持256种优先级,0255 优先级0为最高,优先级255为最低 一般,099分配给系统任务,100255分配给用户任务,嵌入式操作系统,taskSpawn()返回值, 成功:任务ID号 失败:ERROR。返回的ERRNOS可能有, S_intLib_NOT_ISR_CALLABLE,/*程序不能从一个ISR中调用*/ S_objLib_OBJ_ID_
17、ERROR, /*不正确的任务ID*/ S_smObjLib_NOT_INITIALIZED,/*在指定的分区中,没有足够的内存用于发起任务*/ S_memLib_NOT_ENOUGH_MEMORY,/*没有足够的内存发起任务*/ S_memLib_BLOCK_ERROR,/*不能够对内存分区互斥访问*/ S_taskLib_ILLEGAL_PRIORITY /*非法的优先级*/,嵌入式操作系统, 在源代码中使用TaskSpawn创建新任务, 在Tornado Shell中, 使用TaskSpawn创建新任务 使用i查看系统中的任务(演示),嵌入式操作系统, taskSpawn()中包含了一些
18、低级的操作,包括初始化和激活一个任务 taskInit() taskActivate(),嵌入式操作系统,taskInit()初始化一个任务,STATUS taskInit(WIND_TCB *pTcb, /*新任务的TCB地址*/char *name, 允许不指定任务名,由系统自动命名/*新任务的名字*/int priority,/*新任务的优先级*/int options,/*任务选项字*/char *pStackBase,/*任务堆栈基地址*/初始化指定的内存区域作为任务的堆栈和控制块,而不像taskSpawn()那样由系int stackSize,/*堆栈大小*/FUNCPTR ent
19、rypt, 统自动分配/*任务入口*/int arg1,arg2,arg3,arg4,arg5,/*入口参数*/可以方便应用进行调试,并将堆栈分配在指定位置int arg6,arg7,arg8,arg9,arg10),嵌入式操作系统, taskInit的返回值: 成功:OK 任务不能初始化则:ERROR。可能返回的ERRNOS值有:, S_intLib_NOT_ISR_CALLABLE/*程序不能从一个ISR中调用*/ S_objLib_OBJ_ID_ERROR/*不正确的任务ID*/,嵌入式操作系统,taskActivate()激活一个任务, STATUS taskActivate(int
20、tid) taskActivate()激活由taskInit()创建的任务,其参数是taskInit()中第一个参数任务TCB的地址,强制类型转换如下:, tid = (int) pTcb;, 注意:当应用需要对任务定位和激活进行控制时,才使用这两个函数,通常使用taskSpawn()就可以了,嵌入式操作系统,管理任务名称和ID号的函数, ,由任务号得到任务名 taskName()由任务名得到任务ID号 taskNameTold() taskIDSelf()得到任务自身的ID号 taskIdVerify()证实一个特定任务的存在(由任务ID指定),嵌入式操作系统,任务选项相关函数, 尽管Tas
21、kSpawn()中options参数指定的新任务的选项,使用下列函数可以动态读取或设置指定任务的选项 taskOptionsGet():获取任务选项 taskOptionsSet():设置任务选项, 当前只有VX_UNBREAKABLE选项可以改变,嵌入式操作系统,获取任务信息, ,taskIDListGet():获取所有活动任务的ID号 taskInfoGet():得到指定任务的信息 taskPriorityGet():查看指定任务的优先级 taskRegsGet():查看任务的寄存器 taskRegsSet():设置任务的寄存器 taskIsSuspended():查看指定任务是否挂起 t
22、askIsReady():查看指定任务是否就绪 taskTCB:得到任务控制块指针,嵌入式操作系统,taskSpawn应用实例1,嵌入式操作系统, 结果演示,嵌入式操作系统, 仿真器上显示信息:,嵌入式操作系统, 将s2_tasks中的优先级101改为101-i,嵌入式操作系统, 演示结果,嵌入式操作系统,taskSpawn应用实例2,嵌入式操作系统, 演示结果,嵌入式操作系统, 仿真器上显示信息:,嵌入式操作系统,2.2 任务删除和删除安全, 任务可以动态地从系统中删除 删除任务的函数调用,若任务的入口函数指定返回,则将隐含调用exit(); 另外,任务可以在任何时候调用exit杀死自身;,
23、 exit():终止任务自身的执行,释放所占用的内存(stack和TCB) taskDelete():终止一个指定任务,释放所占用的内存(同上),任务可以在任何时候调用taskDelete删除其他任务,任务终止时,其执行时任务分配的内存不会被释放,如malloc() 分配的内存,必须由任务自身编程释放。,嵌入式操作系统,taskDelete应用实例,延迟0.5秒,嵌入式操作系统,嵌入式操作系统, 演示结果,嵌入式操作系统, 仿真器上显示信息:,嵌入式操作系统, 注意:不要在一个不合适的时刻删除任务,在删除之前,该任务必须释放它所持有的所有资源 保护任务不被删除的函数调用任务访问临界区时就需要这
24、种保护。,例如,为了对某些数据结构互斥访问,任务可能取得一个信号量。 但若正在临界区执行的任务被删除,会导致这个任务无法完成临界 区的访问,从而使得该数据结构可能处于一种被破坏或不一致的状 taskSafe():保护任务不被删除 态。 taskUnsafe():解除任务保护此外,由于该任务没有释放信号量,其他任务将无法获得信号量, 从而导致该临界资源不可用。,使用taskDelete()删除另一个被保护的任务,会导致调用 者任务被阻塞,直到被保护的任务解除保护,任务保护使用一个计数器实现保护的嵌套,仅 当计数器为0时才真正的解除保护,嵌入式操作系统, 下面的代码段说明如何使用taskSafe(
25、)和taskUnsafe()来保护一段临界区代码,taskSafe(); semTake(semID, WAIT_FOREVER);/*Block until semaphore available*/ 临界区操作代码 semGive(semID); /*Release semaphore*/ taskUnsafe();,嵌入式操作系统,2.3 任务运行的控制, 下列函数用于控制任务的执行,VxWorks的调试功能希 望能够挂起/恢复任务的 执行,从而可以冻结任 务的执行状态,终止任务,然后使用原 有参数重新创建任务。,提供一个简单的任务睡 眠机制。,区别,taskDelay()将会导致任务被
26、移到相同优先级就绪队列的尾这是一个POSIX函数, 部,例如taskDelay(0)可以将CPU交给同优先级的另一个任务与taskDelay()以下调用将任务延时半秒:一样可以实现延时,但,延时单位不同,可以直 接指明延时。,而调用nanosleep实现延时0被认为是错误的,嵌入式操作系统,taskResume()taskSuspend(),taskResume()/taskActivate(),taskSuspend(),taskSuspend(),taskResume(),挂起,阻塞,就绪,睡眠,taskDelay() 延时已到,执行,taskRestart(),嵌入式操作系统,应用实例1
27、,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统, 演示结果,嵌入式操作系统, 仿真器上显示信息:,嵌入式操作系统, 将taskResume换成taskActivate,结果一样,嵌入式操作系统,应用实例2,嵌入式操作系统,不能延迟到myFunc任务已结束,嵌入式操作系统, 演示结果,嵌入式操作系统, 仿真器上显示信息:,嵌入式操作系统,2.4 任务扩展函数, 有时任务需要在任务创建、删除或上下文切换时增加相应的处理,又不需要修改内核VxWorks的内核wind提供钩子函数机制实现上述目标,使得当任务创建、上下文切换、删除时调用用户附加的函数 下列函数可以设置任务创建/切换/删除时的钩子函数,
28、嵌入式操作系统,taskHookLib,所有HOOK函数的入参都是函数指针,嵌入式操作系统, 由于用于任务切换时的钩子函数只能运行在内核上下文中,因此这个钩子函数能够调用的函数调用有限制,只能是:,缓冲区管理库协处理器(浮点)状态的保存和恢复,链表操作库,体系结构无关的中断例程库,C的数学计算库 环形缓冲区操作库,任务管理库,出错处理,嵌入式操作系统,应用实例,嵌入式操作系统,在任务创建时,就会调用myTaskHook, 演示结果 Shell下输出信息:,嵌入式操作系统, 仿真器输出信息:,嵌入式操作系统,2.5 代码的共享和重入, VxWorks提倡:单个子程序的备份或子程序库被多个不同的任
29、务调用 定义:一个被多个任务调用的单个备份成为共享代码,VxWorks动态链接功能很容易实现代码共享,嵌入式操作系统,重入, 共享代码必须是可重入的: 一个子程序是可重入的,如果该程序的单个备份可以被多个任务同时调用而不会发生冲突 典型的冲突: 对全局或静态变量的修改 VxWorks的很多子程序是可重入的 惯例:所有somename_r()命名的子程序被认为是不可重入的 VxWorks的I/O和驱动程序是可重入的,嵌入式操作系统, 大部分VxWorks函数使用下列3种重入技术:, 动态堆栈变量, 这种函数一般是纯代码,除动态堆栈变量外没有自己的数据,以调用者提供的数据为参数进行操作。, 受信号
30、量保护的全局和静态变量, 这种函数一般含有公共数据,在调用时,必须借助于互斥机制,禁止任务同时在代码临界区域内执行,明确地实现重入。, 任务变量, 一些可被多个任务同时调用的程序,程序中的全局变量或静态变量对每次任务的调用需要不同的值。,嵌入式操作系统,VxWorks与Linux比较, 任务创建函数:taskSpawn()与fork()/exec(), 在fork/exec模型下,先调用fork函数为新任务创建一份与父任务完全相同的内存空间,后调用exec函数装入新任务代码,并用它来覆盖原有的属于父任务的内容。这样做的好处是如果需要,可以从父任务那里继承代码、数据等属性。 在spawn模型下,
31、摈弃了继承的功能,在创建新任务时,直接为它分配全新的地址空间,然后将新代码装入并运行。,嵌入式操作系统,3、VxWorks任务调度, 任务调度策略 任务调度时机 抢占上锁,嵌入式操作系统,3.1 任务调度策略, 调度是针对多任务而言的 调度是指:根据一定的约束规则,将CPU分配给符合条件的任务使用 上述约束规则就是所谓的调度策略(或算法), Wind内核默认采用基于优先级的抢占式调度Priority-based preemptive scheduling 同时还使用轮转(Round-Robin)调度算法,嵌入式操作系统,任务队列, activeQHead, 记录了一个线程从生成到删除过程中的每
32、一个任务信息 ,是一个FIFO队列, readyQHead, 记录所有就绪任务,是一个优先级队列, tickQHead, 记录所有延迟状态的任务,是一个优先级队列, pendQHead, 记录所有阻塞状态的任务,是一个优先级队列, WorkQ, 记录所有中断发起的任务,是一个环形队列,嵌入式操作系统,控制任务调度的几个函数, kernelTimeSlice(), taskPrioritySet(), taskLock(), taskUnlock(),控制轮转调度,改变任务的优先级,禁止任务调度,允许任务调度,嵌入式操作系统,基于优先级的抢占式任务调度, 基于优先级的抢占式任务调度 系统中的每个
33、任务都拥有一个优先级 任意时刻,内核将CPU分配给处于就绪态的优先级最高的任务运行 抢占:一旦内核发现有一个比当前正在运行的任务的优先级高的任务就绪,内核立即保存当前任务的上下文,切换到这个高优先级任务的上下文中运行,嵌入式操作系统,嵌入式操作系统,任务优先级, VxWorks支持256个优先级,编号0255,优先级0最高,255最低,一般099分配给系统任务,100255分配给用户任务。, 任务的优先级在创建时指定 任务可以调用taskPrioritySet改变自己的优先级,嵌入式操作系统,应用示例, 下面程序,创建了3个优先级各不相同的任务:,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统
34、,嵌入式操作系统, 演示结果:,嵌入式操作系统, 如何修改程序,使得任务的执行顺序变为:taskOne,taskTwo,taskThree?,嵌入式操作系统, 修改程序,使得taskOne、taskTwo同时具有最高优先级运行:,嵌入式操作系统, 演示结果,嵌入式操作系统, 基于优先级的抢占是任务调度的缺陷:当多个相同优先级的任务需要共享一台处理器时,如果某个执行的任务永不阻塞,那么他将一直独占处理器,其它相同优先级的任务就没有机会执行。,嵌入式操作系统,轮转调度, 轮转调度通常配合基于优先级的抢占式调度进行 轮转调度:让优先级相同的、处于就绪态的任务公平地共享CPU 轮转调度使用时间片来分配
35、CPU, 每个任务执行一个预先确定的时间段(即时间片) 在大多数系统里,并不一定需要使用轮转调度算法。但在相同代码被多份复制执行时,如在用户接口任务内执行时,需要使用轮转调度算法,嵌入式操作系统, VxWorks中,调用函数kernelTimeSlice()来实现轮转调度 此函数位于kernelLib库中 参数为时间片的长度(tick数)(即:在某个任务放弃CPU给另一个同优先级的任务之前,系统允许它运行的最大时间长度)如kernelTimeSlice(sysClkRateGet()/2)表示时间片为0.5秒 kernelTimeSlice(0)关闭时间片轮转调度策略,嵌入式操作系统, 使用轮
36、转调度算法时,每个任务都有一个运行时间计数器, 随着系统时钟增加而增加 达到规定的值(时间片的值)时,清0 此时,任务放到所在优先级队列的尾部 一个新加入的任务放在所属优先级队列的尾部,计数器初始为0 当任务被阻塞或者被更高优先级的任务抢占,将保存其时间计数值,并且在其重新执行时恢复计数,嵌入式操作系统,嵌入式操作系统,应用实例, 下面的例子创建三个优先级相同的任务,分别向控制台输出他们的任务id号和任务名。, s5_rrsched()调用kernelTimeSlice()允许系统使用轮转调度。 本例中使用的时间片TIMESLICE为1/60秒(函数sysClkRateGet()返回每秒的时钟
37、tick数), 在设置了调度时间片后,程序发起三个任务,注意:必须保证发起的任务优先级要低于100。, 另外为了演示时间片轮转的效果,要保证任务具有足够的执行时间,在本例中使用一个循环次数为LONG_TIME的长循环。,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统,嵌入式操作系统, 演示结果:,嵌入式操作系统, 增加第四个任务,其优先级为80,他和其他任务输出相同的信息。,嵌入式操作系统, 取消时间片轮转: 第一种方法:, 第二种方法:,嵌入式操作系统, 演示结果,嵌入式操作系统,任务切换, 任务切换:终止正在运行的任务(当前任务),转而去运行另外一个任务 任务的切换实质就是
38、断点数据的切换,需要完成以下工作:,把被终止的任务断点指针(PC)保存到任务堆栈中把处理器通用寄存器的内容保存到任务堆栈中把被终止的任务堆栈指针当前值(SP)保存到该任务的TCB中获得待运行任务的TCB使处理器通过TCB获得待运行任务的SP把待运行任务堆栈中通用寄存器的内容回复到处理器的通用寄存器中 使处理器获得待运行任务的断点指针(PC), ,嵌入式操作系统,3.2 任务调度时机,本章难点, 三个关键函数, reschedule intExit windExit,嵌入式操作系统, 调度时机, ,任务相关的操作:生成/删除/挂起/恢/Lock/Unlock WD的创建/开始和销毁 TICK时钟
39、中断 信号量的某些操作Give/Take Event的发送和接受 MsgQ销毁 Posix消息队列的销毁/接受和发送 Posix的mutex的销毁/锁定/解锁 中断执行退出,嵌入式操作系统,任务管理中函数之间的关系,嵌入式操作系统,3.3 抢占上锁, 在实际应用中,有时候需要避免抢占,以免发生不合理的抢占或发生一些意想不到的情况 Wind的调度器提供taskLock()和taskUnlock()来禁止/允许抢占:,嵌入式操作系统, 当一个任务调用taskLock(),将会禁止抢占,在该任务执行时,将不会发生基于优先级的抢占 注意:禁止抢占只能防止任务的上下文切换,不能禁止中断 禁止抢占可以用来实现互斥 但是,应当尽量使禁止抢占的时间最小,嵌入式操作系统,任务调度方面与Linux的比较, 任务的实时优先级数, VxWorks任务的优先级0255,数值越小优先级越高 Linux的实时进程优先级099,数值越大优先级越高, 调度策略的种类, Linux支持SCHED_RR、SCHED_FIFO、SCHED_OTHER三种调度策略 VxWorks只支持前两种,嵌入式操作系统, 调度策略所基于的对象, VxWorks的调度策略不是基于某个任务的,而是针对整个系统的所有任务 Linux的调度策略是基于进程的,某个进程的调度策略的设置不影响其他进程,嵌入式操作系统,