任务是代码运行的一个映象,从系统的角度看,任务是竞争系统资源的最小运行单元。任务可以使用或等待CPU、I/O设备及内存空间等系统资源,并独立于其它任务,与它们一起并发运行(宏观上如此)。VxWorks内核使任务能快速共享系统的绝大部分资源,同时有独立的上下文来控制个别线程的执行。
1. 任务结构
多任务设计能随时打断正在执行着的任务,对内部和外部发生的事件在确定的时间里作出响应。VxWorks实时内核Wind提供了基本的多任务环境。从表面上来看,多个任务正在同时执行,实际上,系统内核根据某一调度策略让它们交替运行。系统调度器使用任务控制块的数据结构(简记为TCB)来管理任务调度功能。任务控制块用来描述一个任务,每一任务都与一个TCB关联。TCB包括了任务的当前状态、优先级、要等待的事件或资源、任务程序码的起始地址、初始堆栈指针等信息。调度器在任务最初被激活时以及从休眠态重新被激活时,要用到这些信息。
此外,TCB还被用来存放任务的"上下文"(context)。任务的上下文就是当一个执行中的任务被停止时,所要保存的所有信息。在任务被重新执行时,必须要恢复上下文。通常,上下文就是计算机当前的状态,也即各个寄存器的内容。如同在发生中断所要保存的内容一样。当发生任务切换时,当前运行的任务的上下文被存入TCB,将要被执行的任务的上下文从它的 TCB中取出,放入各个寄存器中。于是转而执行这个任务,执行的起点是前次它在运行时被中止的位置 VxWorks中,内存地址空间不是任务上下文的一部分。所有的代码运行在同一地址空间。如每一任务需各自的内存空间,需可选产品VxVMI的支持。
2.任务状态和状态迁移
实时系统的一个任务可有多种状态,其中最基本的状态有四种:
就绪态(Ready):任务只等待系统分配CPU资源;
悬置态(Pend):任务需等待某些不可利用的资源而被阻塞;
休眠态(Suspend):如果系统不需要某一个任务工作,则这个任务处于休眠状态;
延迟态(Delay):任务被延迟时所处状态;
当系统函数对某一任务进行操作时,任务从一种状态迁移到另一状态。处于任一状态的任务都可被删除。
状态迁移
就绪态(Ready) ----> 悬置态(Pend) semTake()/msgQReceive()
就绪态(Ready) ----> 延迟态(Delay) taskDelay()
就绪态(Ready) ----> 休眠态(Suspend) taskSuspend()
悬置态(Pend) ----> 就绪态(Ready) semGive()/msgQSend()
悬置态(Pend) ----> 休眠态(Suspend) taskSuspend()
延迟态(Delay) ----> 就绪态(Ready) expired delay
延迟态(Delay) ----> 休眠态(Suspend) taskSuspend()
休眠态(Suspend) ----> 就绪态(Ready) taskResume()/taskActivate()
休眠态(Suspend) ----> 悬置态(Pend) taskResume()
休眠态(Suspend) ----> 延迟态(Delay) taskResume()
3.任务调度策略
多任务调度须采用一种调度算法来分配CPU给就绪态任务。Wind内核采用基于优先级的抢占式调度法作为它的缺省策略,同时它也提供了轮转调度法。
基于优先级的抢占式调度,它具有很多优点。这种调度方法为每个任务指定不同的优先级。没有处于悬置或休眠态的最高优先级任务将一直运行下去。当更高优先级的任务由就绪态进入运行时,系统内核立即保存当前任务的上下文,切换到更高优先级的任务。
Wind内核划分优先级为256 级(0~255)。优先级0为最高优先级,优先级255为最低。当任务被创建时,系统根据给定值分配任务优先级。然而,优先级也可以是动态的,它们能在系统运行时被用户使用系统调用taskPrioritySet()来加以改变,但不能在运行时被操作系统所改变。
轮转调度法,分配给处于就绪态的每个同优先级的任务一个相同的执行时间片。时间片的长度可由系统调用KernelTimeSlice()通过输入参数值来指定。很明显,每个任务都有一运行时间计数器,任务运行时每一时间滴答加1。一个任务用完时间片之后,就进行任务切换,停止执行当前运行的任务,将它放入队列尾部,对运行时间计数器置零,并开始执行就绪队列中的下一个任务。当运行任务被更高优先级的任务抢占时,此任务的运行时间计数器被保存,直到该任务下次运行时。
4.抢占禁止
Wind内核可通过调用taskLock()和taskUnlock()来使调度器起作用和失效。当一个任务调用taskLock()使调度器失效,任务运行时没有基于优先级的抢占发生。然而,如果任务被阻塞或是悬置时,调度器从就绪队列中取出最高优先级的任务运行。当设置抢占禁止的任务解除阻塞,再次开始运行时,抢占又被禁止。这种抢占禁止防止
任务的切换,但对中断处理不起作用。
5.异常处理
程序代码和数据的出错,如非法命令、总线或地址错误、被零除等。VxWorks异常处理包,一般是将引起异常的任务休眠,保存任务在异常出错处的状态值。内核和其它任务继续执行。用户可借助Tornado开发工具,查看当前任务状态,从而确定被休眠的任务。
6.与任务相关函数
VxWorks内核的任务管理提供了动态创建、删除和控制任务的功能,具体实现通过
如下一些系统调用:
taskSpawn() 创建(产生并激活)新任务
taskInit() 初始化一个新任务
taskActivate() 激活一个已初始化的任务
taskName() 由任务ID号得到任务名
taskNameToId() 由任务名得到任务ID号
taskPriorityGet() 获得任务的优先级
taskIsSuspended() 检查任务是否被悬置
taskIsReady() 检查任务是否准备运行
taskTcb() 得到一个任务控制块的指针
taskDelete() 中止指定任务并自由内存(仅任务堆栈和控制块)
taskSafe() 保护被调用任务防止被删除
taskSafe() 解除保护被调用任务
taskSuspend() 悬置一个任务
taskResume() 恢复一个任务
taskRestart() 重启一个任务
taskDelay() 延迟一个任务