3.3.1多道程序技术
3.3.2进程、线程和任务
1.进程
一个进程就是一个正在运行的程序。
一个进程至少包括以下内容:
(1 )相应的程序:相应的代码和数据。
(2 )CPU上下文:程序运行时,CPU中含有各种寄存器的当前值。
包括程序计数器,用于记录将要取出的指令的地址;
程序状态字PSW,用于记录处理器的运行状态;
通用寄存器,用于存放数据和地址;
段寄存器,用于存放程序中各个段的地址;
栈指针寄存器,用于记录栈顶的当前地址。
(3 )一组系统资源:包括用于管理的数据结构、进程的内存地址空间、进程正在使用的文件等等。
总之,进程包含了正在运行的一个程序的所有状态信息。
进程与程序的区别
(1 )程序有两部分组成:代码和数据,是静态概念
进程也有两部分组成:程序和该程序的上下文。
(2 )进程和程序之间并不是一一对应的。一个进程在运行的时候,可以启动一个或者多个程序;反之,同一个程序,也可能有多个进程,同时执行。
(3 )程序可以作为一种软件资源长期存放,而进程则是一次执行过程。
进程的三个特性
(1 )动态性 进程是一个正在执行的程序,而程序的运行状态是不断变化的,每当发生一次函数调用,就会在栈中分配一个空间,用来存放此次函数
调用的参数和局部变量,而当函数调用结束后,这块栈空间就会被释放掉,即一切都在变化之中,不变的只有一些只读的内容,如程序的代码。
(2 )独立性 一个是进程,是一个独立的实体,是计算机系统资源的使用单位,每个进程都有自己运行的上下文和内部状态,在它运行的时候,独立于其他进程。
(3 )并发性 从宏观上来看,在系统中,同时有多个进程存在,它们相互独立的运行。
一个进程的运行上下文当中有很多其他的资源,如PSW寄存器、各种通用寄存器、栈指针寄存器等,它们的使用方式都是类似的,即物理上的硬件寄存 器只有一个,但每一个进程都有相互独立逻辑上的寄存器。
2.线程
概念:
线程 就是进程当中的一条执行流程。
进程 线程+资源平台
3.任务
系统不同,任务的概念略有差异,在VxWorks中、UCOS-II 、Jbed中,任务的概念类似于线程(具体可以参见教科书上的列子);
而在一些嵌入式Linux中,任务的概念类似于进程。
3.3.3 任务的实现
1.任务的层次结构
在多道程序的嵌入式操作系统中,同时存在着多个任务,这些任务之间的结构一般为层状结构,存在着父子关系。当嵌入式内核刚刚启动的时候,
只有一个任务存在,然后由该任务派生出所以其他的任务。
2.任务的创建与终止
任务的创建有三个途径:
(1 ) 系统初始化
(2 ) 任务运行过程中创建
(3 ) 用户提出请求
上面三种途径归结成一种,也就是在一个已经存在的任务当中,通过调用相应的系统函数,来创建一个新的任务。
任务的终止,可能有多种原因,如下面三种情况
(1 )正常退出
(2 )错误退出
(3 )被其他任务踢出
注意:在嵌入式系统当中,尤其是一些控制系统,它的某些任务被设计为“死循环”的模式,一直循环下去,不会终止。
3.任务的状态
(1 )运行状态
(2 )就绪状态 任务已经具备了运行的条件,但是由于CPU较忙,正在运行其他任务,暂时不能运行。不过只要把CPU分给它,它就能够立刻运行。
导致该状态的原因是系统不给CPU的时间。
(3 )阻塞状态 也叫等待状态,该状态的出现,是因为自身的原因。
4.任务的状态
运行→阻塞
运行→就绪
就绪→运行
阻塞→就绪
以上这些状态的转换,完全是自动运行,有操作系统完成,对于用户和进程本身,是意识不到的。
4.任务控制块(TCB)
就是在操作系统中,用来描述与管理一个任务的数据结构,系统为每一个任务都维护了一个相应的TCB,用来保存该任务的各种信息。
TCB的内容主要包括:
(1 )任务的管理信息 任务ID、任务状态、任务的优先级、任务的调度信息、任务的时间统计信息、各种队列指针等等。
(2 )CPU上下文信息 各种CPU寄存器的当前值,包括通用寄存器、PC寄存器、程序状态字、栈指针等等,在实际的嵌入式系统中,
CPU上下文信息不一定直接存放在TCB中,而是存放在栈当中,可以通过相应的栈指针来访问。
(3 )资源管理信息 如段表地址、页表地址、等存储管理方面的信息,根目录、文件描述等文件管理方面的信息。
当需要创建一个新任务的时候,就为它生成一个TCB,初始化TCB内容,当要终止一个任务的时候,主要回收它的TCB就可以了,
对于任务的组织与管理,都是通过TCB来实现。
5.任务切换
6.任务队列
3.3.4 任务的调度
1.任务调度概述
对于就绪队列当中的那些任务,应该选择哪一个去运行?在操作系统中,负责去做出这个选择的那一部分程序,就称为调度器,
而调度器在决策过程中采用的算法,就称为调度算法。从资源管理的角度来看,也可以把调度器看成是CPU这个资源的管理者。
(1 )任务调度的时机
(2 )任务调度的方式
不可抢占式
可抢占式
实时操作系统,大多采用可抢占式的。
(3 )调度算法的性能指标
响应时间 调度器为一个就绪任务进行上下文切换的时,所需要的时间,以及任务在就绪队列中的等待时间。
周转时间 一个任务从提交到完成所经历的时间。
调度开销 调度器在做出调度决策时,所需要的时间和空间开销。
公平性 大致相当的两个任务所得到的CPU时间也应该大致相同,要防止饥饿,即某一个任务始终得不到处理器去运行。
均衡性 尽可能使整个系统的各个部分(CPU、IO)都忙起来,提高系统资源的使用效率。
吞吐量 单位时间内完成的任务数量。
2.先来先服务算法 也叫FCFS算法 即FIFO,是一种不可抢占的调度方式。该算法,一般周转时间比较长。
3.短作业优先算法 即SJF算法
不可抢占方式
可抢占式算法
4.时间片轮转算法 也叫RR算法
时间片轮转算法的优点:
公平性 假设有n个任务,则每个任务得到的时间为1/n;
活动性 假设时间片大小为q,则每个任务最多等待(n-1)q长的时间后,就可以再次运行下去。,综合各方面因素,一般选择时间片q的大小
为20~50ms。
5.优先级算法 分为静态优先级方式和动态优先级方式。
3.3.5 实时系统调度
1.任务模型
2.RMS算法
3.EDF算法
3.3.6 任务间的同步与互斥
1.任务之间的关系
相互独立、任务互斥、任务同步、任务通信
2.任务互斥
把一个任务在运行过程中所做的各种事情分为两类:第一类是任务内部的计算或者其他一些事情,这些事情,肯定不会导致竞争条件的出现;
第二类是对共享资源进行访问,这些访问可能会导致竞争条件的出现。我们把相应的那一部分程序称为临界区,把需要互斥访问的共享资源称为
临界资源。互斥访问的四个条件如下:
(1 )在任何时候,最多只能允许有一个任务位于它的临界区当中。
(2 )不能事先假定cpu的个数和系统运行速度。
(3 )如果某一个任务没有位于它的临界区中,它不能妨碍其他任务去访问临界资源。
(4 )任何一个任务进入临界区的请求必须在有限的时间内满足,不能无限期的等待。
3.任务互斥的解决方案
(1 )关闭中断法
本方法多用在一些操作系统的内核中,使内核在处理一些关键性的敏感数据时,不受其他任务的干扰。
(2 )繁忙等待法
有多种实现的方案,如加锁标志位法、强制轮流法、Peterson算法、TSL算法指令等等。
4.信号量
该方法产生于1965年,基本思路是使用一种新的变量类型,即信号量来记录当前可用的资源的数量。
方式一:信号量的取值必须大于等于0。
方式二:信号量的取值可正可负。如果是正数或0,其含义与方式一是相同的;如果是负数,则它的绝对值就代表正在等待进入临界区的任务个数。
信号量是有操作系统来维护的,任务不能直接去修改它的值,只能通过初始化和两个标准语句(即P、V原语)来对它进行访问。
采用信号量来实现任务之间的互斥,优点有两个:一是可以设置信号量的计数值,从而允许多个任务同时进入进入临界区;
二是当一个任务暂时无法进入临界区的时候,它会被阻塞起来,从而让出CPU给其他任务。
在ucOS-II当中,osSemCreate函数表示创建一个信号量,osQuePend函数类似于P操作,osSemPost类似于V操作。
5.任务同步
6.死锁
7.信号
3.3.7 任务间通信
1.共享内存
2.消息传递
3.管道
管道通信以文件系统为基础,所谓管道即连接两个任务之间的一个打开的共享文件,专用于任务之间的数据通信。发送任务从管道的一端写入数据,
接收任务从管道的另一端按先进先出的顺序读出数据流。管道的读写操作即为文件的读写操作,数据流的长度和格式没有限制。