uc/os-II 源码剖析笔记(1)——几个RTOS里面的基本概念(一)

来源:互联网 发布:青岛网络教育 编辑:程序博客网 时间:2024/06/05 05:41

一. 实时操作系统(RTOS)

 

大概分为两种:硬实时和软实时;硬实时对时间要求较为严格,它要求各任务不仅要执行无误而且要做到准时;软实时对时间要求较低,它是以各任务尽可能快的完成为标准,而并未强制规定任务必须在规定的时间内完成。

 

现如今的绝大多数OS体系是硬实时和软实时相结合的策略。

 

 

二.前后台系统

 

应用程序是一个大循环,里面有各个需要执行的任务,这部分可看成是后台系统;对于一些重要的实时性要求强的任务则放到中断函数中去执行,这部分就是前台系统。一般的应用不复杂的操作系统都会设计成前后台系统,典型的应用为:51单片机的大多数OS就采用这种体系。

 

 

三.代码的临界段

 

是代码执行的最小实体,这种代码要求在执行时不可中断,也可称作原语。为了实现系统在执行这些代码时不会产生中断,则要求在进入临界段代码时关掉CPU中断,在退出临界段代码时再打开CPU中断。

 

四.资源和共享资源

 

本质上,代码所用到的一些实体都被称作资源,硬件如打印机,键盘,显示器等;甚至于数组,一些数据结构等等。 而共享资源是指多个任务公用的资源,这种资源在使用时要求只有一个任务在用,这就涉及到“互斥”,待以后具体讨论。

 

五.任务和多任务

 

多任务的的运行依赖于CPU使用一定的任务调度算法,在多个不同任务间进行分时切换;概念上很像前后台系统,只不过后台有多个任务。

 

任务,一个线程就可看做一个任务,是一个简单的程序,该程序可认为在执行时CPU只属于它自己,并且拥有自己的栈空间和寄存器,而每个任务都有自己的优先级,优先级决定着任务的执行时间的先后。 每个任务有5种基本状态;就绪,休眠,挂起,执行,中断。 就绪意味着该程序已经准备好,可以运行,但因为当前CPU被其它任务占用,而排在任务就绪队列中等待自己的时间片的到来;休眠是指该程序因为一些原因而常驻内存,不与CPU打交道,除非被应用程序唤醒。挂起意味着当前任务在等待某个其它任务的通知;执行意味着此任务在占用CPU并执行;最后,中断意味着原来正在运行的任务由于一些原因而被强制不能执行,CPU会去执行相应的中断代码。

 

 

六.任务切换

 

多个任务在执行时由内核来控制每个任务的调度,同时在任务切换时,要将当前任务的所有反应当前状态的寄存器全部该任务自己的任务栈(一般来说是全部寄存器),然后再将下一个任务的任务栈中东西转移到CPU执行下一个任务。

 

七.可剥夺型内核和不可剥夺性内核

 

可剥夺性内核:任务在执行时,如果有一个优先级比当前任务优先级高的任务进入就绪状态,则当前任务会被挂起,进而执行进入就绪态的优先级高的任务,待到此优先级高的任务执行完毕时,先前被挂起的任务才会恢复执行。

 

不可剥夺性内核:任务在执行时,即便有一个优先级比当前任务优先级高的任务进入就绪态,正在执行的任务也不会放弃当前对CPU的占用权,直到此任务执行完毕后自动放弃对CPU的占用权,先前处于就绪态的高优先级任务才会开始执行。不可剥夺性内核由于其对高优先级的时间反应不灵活,而未在商用OS中占有一席之地。

 

 

八.函数的可重入性和不可重入性

 

可重入性函数是指可以被多个任务调用而不用担心其数据遭破坏的函数。如下函数:

 

int  swap(int *a,int *b)

{

       int *p;

      *p=*a;

      *a=*b;

      *b=*p;

}

 

此函数在执行时就不必担心数据会遭到破坏,因为函数中未使用全局变量,局部变量都被保存在堆栈中。

 

在看以下函数:

 

int *p

 

int swap(int *a,int *b)

{

     *p=*a;

     *a=*b;

     *b=*p;

}

 

此函数便是不可重入性函数,在不可剥夺性内核中使用该函数时不必担心数据会遭到破坏,因为不可剥夺性内核由于其只能在执行完当前任务后才允许下一个任务的执行。而对于可剥夺型内核,情况则较为复杂,多任务在执行这段代码时完全有可能发生数据访问不到预期的值的情况。解决这种问题的办法如下:

 

1.   Temp定义为局部变量  

2.调用Swap()函数之前关中断,调动后再开中断         

3.  用信号量禁止该函数在使用过程中被再次调用

 

九.任务优先级

 

多任务OS中,每个任务都有自己的优先级,任务的重要性越高,所赋予的优先级就越高。

 

十.静态优先级和动态优先级

 

静态优先级就是在运行中优先级不可改变,这种优先级在编译时就已确定并不会被修改;而动态优先级在运行时会视情况而被修改,大多数优先级的修改源自于防止优先级的反转。

 

十一.优先级反转

 

在可剥夺型内核中,假设现在有3个任务,分别为T1,T2,T3,其优先级分别为高,中,低;现在T1处于运行态,并且需要一个共享资源的信号量,而此信号量在T3任务中未释放,于是此时T1先挂起,T3开始执行,而T3开始执行时就绪队列中又有优先级比它高的T2任务,于是T3又处于就绪态,T2开始执行,待T2执行完毕后,T3开始执行释放信号量的操作,释放完后T1才开始执行任务直至执行完毕;整个执行过程中T1的优先级实质已经降到了T3的级别,这种情况被称为优先级的反转,在实际应用中,应尽量避免这种情况的发生。 解决的方式是在T3执行前就将其优先级设定为最高级(高于所有的任务),此时就不会存在T2剥夺CPU的情况。

 

在UC/OS-II中,是使用上述解决方式来实现防止优先级的反转;而在许多商用OS中(如WINDOWS),有另外一种解决方式,被称为“优先级的继承”;由于在提高T3的优先级和释放信号量后降低T3优先级会花费一些不必要的时间,于是这种继承性优先级的解决方式便产生,其基本原理为在T1处于挂起态后,由内核将T3优先级转换到与T1同等的优先级,待T3释放信号量后,内核又将其优先级降到原本优先级。