实时系统的特点是,如果逻辑和时序出现偏差将会引起严重后果的系统。能够对外界事件和数据作出快速处理并快速响应。
有两种类型的实时系统:软实时系统和硬实时系统。
1.在软实时系统中系统的宗旨是使各个任务运行得越快越好,并不要求限定某一任务必须在多长时间内完成。
2.在硬实时系统中,各任务不仅要实行无误而且要做到准时。
大多数实时系统是二者的结合。多数实时系统又是嵌入式的。
这意味着计算机建在系统内部,用户看不到有个计算机在系统里面——嵌入式。
一 前后台系统
应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台行为(background)。
中断服务程序处理异步事件,这部分可以看成前台行为(foreground)。
后台也可以叫做任务级。前台也叫中断级
时间相关性很强的关键操作(Critical operation)一定是靠中断服务来保证的
因为中断服务提供的信息一直要等到后台程序走到该处理这个信息这一步时才能得到处理,这种系统在处理信息的及时性上,比实际可以做到的要差。
二 不可剥夺型内核(Non-Preemptive Kernel)
不可剥夺型内核要求每个任务自我放弃CPU 的所有权。不可剥夺型调度法也称作合作型多任务,各个任务彼此合作共享一个CPU。
异步事件还是由中断服务来处理。中断服务可以使一个高优先级的任务由挂起状态变为就绪状态。
但中断服务以后控制权还是回到原来被中断了的那个任务,直到该任务主动放弃CPU 的使用权时,那个高优先级的任务才能获得CPU的使用权。
运行着的任务占有CPU,而不必担心被别的任务抢占。
任务级响应时间要好于前后系统,但仍是不可知的要等当前任务实行完毕,商业App几乎没有不可剥夺型内核。
三 可剥夺型内核
当系统响应时间很重要时,要使用可剥夺型内核。最高优先级的任务一旦就绪,总能得到CPU 的控制权。
当一个运行着的任务使一个比它优先级高的任务进入了就绪态,当前任务的CPU 使用权就被剥夺了,
或者说被挂起了,那个高优先级的任务立即得到了CPU 的控制权。
如果是中断服务子程序使一个高优先级的任务进入就绪态,中断完成时,中断了的任务被挂起,优先级高的那个任务开始运行。
使用可剥夺型内核,最高优先级的任务什么时候可以实行,任务之间切换发生的概率是较高的,存在资源竞争情况发生。
四 实时操作系统基本概念
1 代码临界段
代码的临界段也称为临界区,指处理时不可分割的代码。
一旦这部分代码开始实行,则不允许任何中断打入。为确保临界段代码的实行,在进入临界段之前要关中断,而临界段代码实行完以后要马上开中断。
2 任务
一个任务,也称作一个线程,是一个简单的程序,该程序可以认为CPU 完全只属该程序自己。
实时应用程序的设计过程,包括如何把问题分割成多个任务,每个任务都是整个应用的某一部分,
每个任务被赋予一定的优先级,有它自己的一套CPU 寄存器和自己的栈空间。
典型地、每个任务都是一个无限的循环。
休眠态相当于该任务驻留在内存中,但并不被多任务内核所调度。
就绪态意味着该任务已经准备好,可以运行了,但由于该任务的优先级比正在运行的任务的优先级低,还暂时不能运行。
运行态的任务是指该任务掌握了CPU 的控制权,正在运行中。
挂起状态也可以叫做等待事件态WAITING,指该任务在等待,等待某一事件的发生,
(例如等待某外设的I/O 操作,等待某共享资源由暂不能使用变成能使用状态,等待定时脉冲的到来或等待超时信号的到来以结束目前的等待,等等)。
中断时,CPU 提供相应的中断服务,原来正在运行的任务暂不能运行,就进入了被中断状态。
3 任务切换
当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态(Context),即CPU 寄存器中的全部内容。
这些内容保存在任务的当前状况保存区(Task’sContext Storage area),也就是任务自己的栈区之中。
入栈工作完成以后,就是把下一个将要运行的任务的当前状况从该任务的栈中重新装入CPU 的寄存器,并开始下一个任务的运行。这个过程叫做任务切换。
任务切换过程增加了应用程序的额外负荷。CPU的内部寄存器越多,额外负荷就越重。做任务切换所需要的时间取决于CPU 有多少寄存器要入栈。
4内核
多任务系统中,内核负责管理各个任务,或者说为每个任务分配CPU 时间,并且负责任务之间的通讯。内核提供的基本服务是任务切换。
之所以使用实时内核可以简化应用系统的设计,是因为实时内核允许将应用分成若干个任务,由实时内核来管理它们。
内核本身也增加了应用程序的额外负荷,代码空间增加ROM 的用量,内核本身的数据结构增加了RAM的用量。
但更主要的是,每个任务要有自己的栈空间,这一块吃起内存来是相当利害的。内核本身对CPU 的占用时间一般在2 到5 个百分点之间。
单片机一般不能运行实时内核,因为单片机的RAM 很有限。
通过提供必不可缺少的系统服务,诸如信号量管理,邮箱、消息队列、延时等,实时内核使得CPU 的利用更为有效。
5 调度
调度(Scheduler),英文还有一词叫dispatcher,也是调度的意思。这是内核的主要职责之一,就是要决定该轮到哪个任务运行了。
多数实时内核是基于优先级调度法的。每个任务根据其重要程度的不同被赋予一定的优先级。
基于优先级的调度法指,CPU 总是让处在就绪态的优先级最高的任务先运行。然而,究竟何时让高优先级任务掌握CPU 的使用权,
有两种不同的情况,这要看用的是什么类型的内核,是不可剥夺型的还是可剥夺型内核。
6 可重入性(Reentrancy)
可重入型函数可以被一个以上的任务调用,而不必担心数据的破坏。可重入型函数任何时候都可以被中断,一段时间以后又可以运行,而相应数据不会丢失。
可重入型函数或者只使用局部变量,即变量保存在CPU 寄存器中或堆栈中。如果使用全局变量,则要对全局变量予以保护。
不可重入型函数使用任务间公共性的资源,例如:全局变量
假定使用的是可剥夺型内核,中断是开着的,Temp 定义为整数全程变量。
int Temp; //全局变量
void swap(int *x, int *y)
{
Temp = *x;
*x = *y;
*y = Temp;
}
|
将会发生情况:
使用以下技术之一即可使Swap()函数具有可重入性:
把Temp 定义为局部变量
调用Swap()函数之前关中断,调动后再开中断
用信号量禁止该函数在使用过程中被再次调用
7任务优先级
每个任务都有其优先级。任务越重要,赋予的优先级应越高。
静态优先级
应用程序实行过程中诸任务优先级不变,则称之为静态优先级。在静态优先级系统中,诸任务以及它们的时间约束在程序编译时是已知的。
动态优先级
应用程序实行过程中,任务的优先级是可变的,则称之为动态优先级。实时内核应当避免出现优先级反转问题。
时间片调度
当两个或两个以上任务有同样优先级,内核允许一个任务运行事先确定的一段时间,叫做时间额度(quantum),然后切换给另一个任务。也叫做时间片调度。
优先级反转
优先级继承
8 互斥条件
当所有到任务都在一个单一地址空间下,能使用全程变量、指针、缓冲区、链表、循环缓冲区等,使用共享数据结构通讯就更为容易。
虽然共享数据区法简化了任务间的信息交换,但是必须保证每个任务在处理共享数据时的排它性,以避免竞争和数据的破坏。与共享资源打交道时,使之满足互斥条件
最一般的方法有:
关中断
使用测试并置位指令:事件
禁止做任务切换
利用信号量:多值信号量,互斥信号量
使用信号量可以实现任务间的同步或者任务与中断间的同步。
9 任务间的通讯
任务间的或中断服务与任务间的通讯。任务间信息的传递有两个途径:通过全程变量或发消息给另一个任务。
全程变量:
任务只能通过全程变量与中断服务程序通讯。任务并不知道什么时候全程变
量被中断服务程序修改了,除非中断程序以信号量方式向任务发信号或者是该任务以查询方式不断周期性地查询变量的值。
消息邮箱:
要避免这种情况,用户可以考虑使用邮箱或消息队列。
通过内核服务,一个任务或一个中断服务程序可以把一则消息(即一个指针)放到邮箱里去。一个或多个任务可以通过内核服务接收这则消息。
消息队列:
消息队列实际上是邮箱阵列
10 中断
中断是一种硬件机制,用于通知CPU 有个异步事件发生了。中断一旦被识别,CPU 保存部分(或全部)现场(Context)即部分或全部寄存器的值,
跳转到专门的子程序,称为中断服务子程序(ISR)。中断服务子程序做事件处理,处理完成后,程序回到:
在前后台系统中,程序回到后台程序
对不可剥夺型内核而言,程序回到被中断了的任务
对可剥夺型内核而言,让进入就绪态的优先级最高的任务开始运行
|