进程调度
任务调度主要是协调任务对计算机系统内资源(如内存、i/o设备、cpu)的争夺
使用。进程调度又称为cpu调度,其根本任务是按照某种原则为处于就绪状态
的进程分配cpu。由于嵌入式系统中内存和i/o设备一般都和cpu同时归属于
某进程,所以任务调度和进程调度概念相近,很多场合不加区分,下文中提到的
任务其实就是进程的概念。
进程调度可分为"剥夺型调度"和"非剥夺型调度"两种基本方式。所谓"非剥夺型
调度"是指:一旦某个进程被调度执行,则该进程一直执行下去直至该进程结束,
或由于某种原因自行放弃cpu进入等待状态,才将cpu重新分配给其他进程。
所谓"剥夺型调度"是指:一旦就绪状态中出现优先权更高的进程,或者运行的进
程已用满了规定的时间片时,便立即剥夺当前进程的运行(将其放回就绪状态),
把cpu分配给其他进程。
作为实时操作系统,uc/os是采用的可剥夺型实时多任务内核。可剥夺型的实时
内核在任何时候都运行就绪了的最高优先级的任务。uc/os中最多可以支持64
个任务,分别对应优先级0~63,其中0为最高优先级。调度工作的内容可以分
为两部分:最高优先级任务的寻找和任务切换。
其最高优先级任务的寻找是通过建立就绪任务表来实现的。uc/os中的每一个任
务都有独立的堆栈空间,并有一个称为任务控制块tcb(task control block)数据
结构,其中第一个成员变量就是保存的任务堆栈指针。任务调度模块首先用变量
ostcbhighrdy记录当前最高级就绪任务的tcb地址,然后调用os_task_sw()
函数来进行任务切换。
uclinux的进程调度沿用了linux的传统,系统每隔一定时间挂起进程,同时系
统产生快速和周期性的时钟计时中断,并通过调度函数(定时器处理函数)决定进
程什么时候拥有它的时间片。然后进行相关进程切换,这是通过父进程调用fork
函数生成子进程来实现的。
uclinux系统fork调用完成后,要么子进程代替父进程执行(此时父进程已经
sleep),直到子进程调用exit退出;要么调用exec执行一个新的进程,这个时候
产生可执行文件的加载,即使这个进程只是父进程的拷贝,这个过程也不可避免。
当子进程执行exit或exec后,子进程使用wakeup把父进程唤醒,使父进程继续
往下执行。
uclinux由于没有mmu管理存储器,其对内存的访问是直接的,所有程序中访
问的地址都是实际的物理地址。操作系统队内存空间没有保护,各个进程实际上
共享一个运行空间。这就需要实现多进程时进行数据保护,也导致了用户程序使
用的空间可能占用到系统内核空间,这些问题在编程时都需要多加注意,否则容
易导致系统崩溃。
由上述分析可以得知,uc/os内核是针对实时系统的要求设计实现的,相对简单,
可以满足较高的实时性要求。而uclinux则在结构上继承了标准linux的多任务
实现方式,仅针对嵌入式处理器特点进行改良。其要实现实时性效果则需要使系
统在实时内核的控制下运行,rt-linux就是可以实现这一个功能的一种实时内
核。