vxworks VS linux

以Linux(2.4)版本内核)和VxWorks(5.4版本)为代表,着重分析二者任务调度机制的异同。 

1)多用户性。Linux是多用户操作系统,它使用用户和组标识符来控制进程对系统中文件和映像以及其他资源的访问权限。task_struct中有四对进程和组标识符:进程uid和gid、有效uid和gid、文件系统uid和gid、保留的uid和gid。而VxWorks是单用户的操作系统,任务控制块结构windTcb中没有与用户相关联的数据结构。 
2)文件打开表。Linux的每个进程都拥有一个文件打开表,以记录该进程使用文件的情况, 对应于task_struct中file_ struct 类型的files成员。当进程退出时,内核会自动检查并关闭进程已打开但未显式调用close()关闭的文件。VxWorks的整个系统共用一个文件打开表,每个任务控制块中没有记录该任务已打开的文件信息,因此当某个任务退出时,其已打开的文件自然不会被自动关闭。 
3)任务之间的亲属性。Linux的每个进程都不是孤立地存在于系统中,新的进程创建起就置于一种表示“宗族”和“家谱”的树型组织中,初始化进程init是所有进程的祖先进程。在task_ struct结构中有一组task_struct 类型的指针结构成员,其中P_opptr和P_pptr指向父进程,p_cptr指向最“年轻”的子进程,P_Ysptr和P_osptr则分别指向其“哥哥”和“弟弟”。而VxWorks的任务间没有类似的亲属关系,每一个任务都是平等而独立的,即使一个任务创建并激活一个新的任务,两者之间也不存在父子关系。 
另外,Linux的进程控制块和VxWorks任务控制块的差别还有许多,比如Linux的task_struct中保存的进程杂凑队列的链人指针、线程信息、虚拟内存信息等。 


2.1 VxWorks的任务调度 

2.1.1 VxWorks任务调度时机 
VxWorks中任务调度的时机可分以下两种情况: 
1)同步任务切换,引起的原因是当前运行的任务执行下列操作:①进行阻塞、延迟、挂起的调用;②使更高优先级任务就绪而发生优先级抢占;③降低自身优先级或者退出。 
2)异步任务切换,通常由中断服务使高优先级任务就绪引起。VxWorks的Wind微内核基于优先级抢占调度。并采取单一实地址空间模式,上述引发任务调度的情况发生时,VxWorks内核立即进行任务的调度切换。 

2.1.2 VxWorks任务调度策略 
多任务运行时需要一个调度算法,将CPU分配给就绪的任务。Wind内核默认采用基于优先级的抢占式调度(Priority-based preemptive scheduling)算法,同时也可以选用轮转(Round-robin)调度算法。 
1)基于优先级抢占的任务调度:指每个进程被赋予一个优先级,优先级最高的就绪进程率先执行 可抢占调度(preemptive scheduling)是指允许将逻辑上可运行的进程暂时挂起的策略。VxWorks采用基于优先级抢占的调度算法,系统中的每个任务都拥有一个优先级,内核将CPU分配给处于就绪状态的优先级最高的任务。如果系统内核一旦发现有一个优先级比当前任务的优先级高的任务转变到就绪状态,内核立即保存当前任务的上下文,当前任务状态切换到就绪状态并按优先级插入到相应任务队列的队尾,然后内核切换到这个高优先级任务的上下文中执行。 
Wind内核有256个优先级,编号是0-255,0的优先级最高,255最低。任务的优先级可以在创建时设定,系统默认的任务优先级为100。VxWorks允许任务动态改变自己的优先级,当任务执行时,它可以调用taskPrioritySet()改变自己的优先级。 
2)轮转调度:VxWorks中,基于优先级抢占的调度可以与轮转调度相结合。轮转调度算法试图让优先级相同的、处于就绪状态的任务公平地分享使用CPU资源。如果不使用轮转调度,当系统中存在多个相同优先级的任务时,第一个获得CPU的任务将会独占CPU,如果没有阻塞或其它情况出现,其它相同优先级的任务将得不到运行的机会。 
使用轮转调度时,每个任务被分配一个时间段,称作它的时间片(quantum),即该任务允许运行的时间。在VxWorks系统中,可以调用函数kernelTimeSlice0来选用轮转调度策略,其参数是时间片的长度,该时间片是每一个任务在放弃CPU给另一个相同优先级任务之前,系统允许它运行的时间长度。如果任务在它的时间片中被高优先级的任务抢占,调度器保存它的运行时间计数器,当它再一次符合执行条件的时候,调度器恢复运行时间计数器。 

2.1.3 抢占上锁与中断上锁 
由于所有VxWorks任务共存于单一的线性地址空间,当多个任务共享全局的数据结构时,需要提供对临界区的互斥访问机制。使用信号量对资源上锁是一种比较通用的互斥手段,如POSIX有名信号灯或无名信号灯和System V的信号量集。VxWorks提供了三种类型的信号量:二进制信号量、互斥信号量和计数器信号量。此外,VxWorks在任务调度层次上提供了互斥访问保护的机制:在I临界区内禁止任务的抢占调度,这在VxWorks中称为抢占上锁,具体互斥的实现是将临界区代码包括在两个函数taskLock()和taskUnlock()之间。 
在VxWorks中,不仅任务与任务之间需要考虑互斥,同时任务与中断之间也要考虑互斥。因为中断的优先级高于任何任务,所以抢占上锁虽然保证了任务与任务间的互斥,但并没有保证任务与中断服务程序对I临界区的互斥访问。VxWorks的中断上锁则提供了最强有力的互斥,将临界区代码保护在intLock()和intUnlock()两个函数之间。中断上锁实现的是中断级互斥,在互斥期间,即使外部事件产生而引发相应的中断,系统也不会切换到相应的中断服务程序(iSR)。 
因此,VxWorks的抢占上锁和中断上锁是通过禁止任务抢占或禁止切换到中断服务程序来保护临界区的。同时,这种灵活的互斥手段在临界区中也会影响VxWorks任务的原始调度原则,比如低优先级任务抢占上锁时,就绪任务队列上具有较高优先级的任务却不能即时占有处理机。 

2.2 Linux的进程调度 

2.2.1 Linux进程调度的时机 
Linux进程的调度时机大致分为两种情况:一种是进程自愿调度;另一种是发生强制性调度。首先,自愿的调度随时都可以进行。在内核空间中,进程可以通过schedule()启动一次调度;在用户空间中,可以通过系统调用pause()达到同样的目的。如果要为自愿的暂停行为加上时间限制,在内核中使用schedule_timeout(),而在用户空间则使用nanosleep()系统调用。Linux中,强制性的调度发生在每次从系统调用返回的前夕,以及每次中断或异常处理返回用户空间的前夕。应注意的是,从内核态返回到用户态是进程调度发生的必要条件,而不是充分条件,还要取决于当前进程task_struct结构中的need_resched是否为1。单CPU条件下,有三种情况可以使当始终比所有的非实时进程都要大,这就保证了实时进程的优先运行。实时进程的counter与nice都与其优先级权值无关,这和普通进程是有区别的, 实时进程task_struct中的nice和counter只与SCHED—RR调度策略进程的时间片计数相关;而对于SCHED—FIFO调度策略的实时进程没有调度的参考意义。 

3 POSlX调度接口 
POSIX1003.1b实时扩展标准定义了进程调度的标准函数接El形式,VxWorks的任务调度和Linux中实时进程的调度都支持POSIX1003.1b标准,但二者在该标准的实现上差异较大,列出如下。 
1)实时优先级数。VxWorks任务的优先级为0-255,Wind内核默认为数值越大,任务优先级越低。Unux实时进程优先级为1~99,数值越大,进程优先级越高。 
2)调度策略的种类。Linux支持SCHED—RR、SCHED—FIFO和SCHED—OTHER的调度策略,而VxWorks只支持前两种策略,不支持SCHED_OTHER策略。另外Linux实时进程和普通进程可以互相转换, 通过SCHED_OTHER 参数调用sched_ setscheduler()函数,可以将Linux实时进程转化为普通进程。通过以SCHEDl-RR或SCHED FIFO 为参数调用sched_ setscheduler()也可以将普通进程转为实时进程。 
3)调度策略所基于的对象。VxWorks的任务调度策略不是基于某个任务的,而是针对整个系统的所有任务。VxWorks下不能通过sched—setscheduler()来改变内核当前的任务调度策略,VxWorks下改变调度策略的唯一手段是通过kernelTimeSlice()函数设置轮转调度的时间片长度来实现的,该时间片长度设为0时。即取消了SCHED—RR策略。Linux中的调度策略是基于进程的,某个进程调度策略的设置不影响其他进程。 


Linux的任务调度

通用Linux系统支持实时非实时两种进程,实时进程相对于普通进程具有绝对的优先级。对应地,实时进程采用SCHED_FIFO或者SCHED_RR调度策略,普通的进程采用SCHED_OTHER调度策略。

在调度算法的实现上,Linux中的每个任务有四个与调度相关的参数,它们是rt_priority、policy、priority(nice)、counter。调度程序根据这四个参数进行进程调度。

SCHED_OTHER调度策略中,调度器总是选择那个priority+counter值最大的进程来调度执行。从逻辑上分析SCHED_OTHER调度策略存在着调度周期(epoch),在每一个调度周期中,一个进程的priority和counter值的大小影响了当前时刻应该调度哪一个进程来执行,其中priority是一个固定不变的值,在进程创建时就已经确定,它代表了该进程的优先级,也代表这该进程在每一个调度周期中能够得到的时间片的多少counter是一个动态变化的值,它反映了一个进程在当前的调度周期中还剩下的时间片。在每一个调度周期的开始,priority的值被赋给counter,然后每次该进程被调度执行时,counter值都减少。当counter值为零时,该进程用完自己在本调度周期中的时间片,不再参与本调度周期的进程调度。当所有进程的时间片都用完时,一个调度周期结束,然后周而复始。另外可以看出Linux系统中的调度周期不是静态的,它是一个动态变化的量,比如处于可运行状态的进程的多少和它们priority值都可以影响一个epoch的长短。值得注意的一点是,在2.4以上的内核中,priority被nice所取代,但二者作用类似

可见SCHED_OTHER调度策略本质上是一种比例共享的调度策略,它的这种设计方法能够保证进程调度时的公平性--一个低优先级的进程在每一个 epoch中也会得到自己应得的那些CPU执行时间,另外它也提供了不同进程的优先级区分,具有高priority值的进程能够获得更多的执行时间。对于实时进程来说,它们使用的是基于实时优先级rt_priority的优先级调度策略,但根据不同的调度策略,同一实时优先级的进程之间的调度方法有所不同:

SCHED_FIFO:不同的进程根据静态优先级进行排队,然后在同一优先级的队列中,谁先准备好运行就先调度谁,并且正在运行的进程不会被终止直到以下情况发生:(1).被有更高优先级的进程所强占CPU;(2).自己因为资源请求而阻塞;(3).自己主动放弃CPU(调用sched_yield)。

SCHED_RR:这种调度策略跟上面的SCHED_FIFO一模一样,除了它给每个进程分配一个时间片,时间片到了正在执行的进程就放弃执行;时间片的长度可以通过sched_rr_get_interval调用得到。


由于Linux系统本身是一个面向桌面的系统,所以将它应用于实时应用中时存在如下的一些问题:

- Linux系统中的调度单位为10ms,所以它不能够提供精确的定时;

- 当一个进程调用系统调用进入内核态运行时,它是不可被抢占的;

- Linux内核实现中使用了大量的锁中断操作会造成中断的丢失;

- 由于使用虚拟内存技术,当发生页出错时,需要从硬盘中读取交换数据,但硬盘读写由于存储位置的随机性会导致随机的读写时间,这在某些情况下会影响一些实时任务的截止期限;

- 虽然Linux进程调度也支持实时优先级,但缺乏有效的实时任务的调度机制和调度算法;它的网络子系统的协议处理和其它设备的中断处理都没有与它对应的进程的调度关联起来,并且它们自身也没有明确的调度机制;

https://www.ibm.com/developerworks/cn/linux/embed/l-realtime/


阅读更多
想对作者说点什么?
相关热词

博主推荐

换一批

没有更多推荐了,返回首页