690 likes | 842 Views
第二章 进程管理. 2.1 进程的基本概念 2.2 进程管理 2.3 进程调度 2.4 进程间的同步与互斥 2.5 进程通讯 2.6 死锁. 2 . 1 进程的基本概念. 程序的顺序执行和并发执行 顺序执行是 单道批处理 系统的执行方式,也用于简单的单片机系统; 现在的操作系统多为 并发执行 ,具有许多新的特征。引入并发执行的目的是为了提高资源利用率。. 程序的顺序执行. 例:程序段 read(disk,&a,4); /* 从磁盘读 a*/ read(tape,&b,4); /* 从带读 b*/
E N D
第二章 进程管理 • 2.1 进程的基本概念 • 2.2 进程管理 • 2.3 进程调度 • 2.4 进程间的同步与互斥 • 2.5 进程通讯 • 2.6 死锁
2.1 进程的基本概念 程序的顺序执行和并发执行 顺序执行是单道批处理系统的执行方式,也用于简单的单片机系统; 现在的操作系统多为并发执行,具有许多新的特征。引入并发执行的目的是为了提高资源利用率。
程序的顺序执行 • 例:程序段 read(disk,&a,4); /*从磁盘读a*/ read(tape,&b,4); /*从带读b*/ c=a+b; printf(“c=%f\n”,c); • 顺序执行的特征 • 顺序性 • 封闭性 • 可再现性
S1 S1 S3 S2 S2 S4 S6 S5 S3 S7 程序并行性表示 1.前驱图 是一个有向无环图,图中每个结点表示一个语句、一段程序或一个进程 有向边< Vi , Vj >表示Vj仅在Vi执行完后才能开始执行 有回路的前驱图 前驱图
COBEGIN s1;s2;…;sn COEND 2.并行语言 类Pascal的并行语句。 COBEGIN / COEND相当于一个括号,表示其中的所有语句s1, s2,… sn可并行执行。
并发执行的条件(Bernstein条件) 1966年,由Bernstein给出并发执行的条件。 • 程序 P(i) 针对变量的读集R(i)和写集W(i) • 条件:任意两个程序P(i)和P(j),同时满足: • R(i)W(j)=; • W(i)R(j)=; • W(i)W(j)=; 前两条保证一个程序的两次读之间数据不变化;最后一条保证写的结果不丢掉。 例:s1: read(disk,&a,4); /*从磁盘读a*/ s2: read(tape,&b,4); /*从带读b*/ s3:c=a+b; R(s1)= W(s1) ={a} s1和s2可并发,s2和s3不可并发
多道程序系统:资源共享;程序的并发运行 例:int N=0; /*全局变量*/ cobegin progam A { while(1){ ….. N++; ….. } } progam B { while(1){ ….. printf(“N=%d\n”,N); N=0; ….. } } coend
并发执行的特征 • 间断(异步)性:“运行-暂停-运行”;并发程序之间依赖相互、相互制约 • 不可再现性 • 并发程序与它的执行过程并非一一对应
进程(PROCESS)的概念 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。 是系统进行资源分配和调度的一个独立单位 进程的定义 是并发程序的一次执行过程,它由一个动作序列组成,每个动作是在某数据集上执行一段程序,整个活动的结果是提供一种系统或用户功能。
进程的特征 • 动态性:产生、执行、暂停、消亡。有一个生存期 • 独立性:是系统进行资源分配和调度的独立单位,是能独立运行的基本单位 • 并发性:程序在建立进程后并发运行 进程=程序+数据+PCB (进程控制块,process control block)
进程与程序的区别 • 进程是动态的,程序是静态的 • 进程是暂时的,程序的永久的 • 进程与程序的组成不同 进程与程序的联系 • 通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。
2.2 进程管理 进程的状态 三种基本调度状态 • 运行状态:进程分配到必要的资源,在CPU上执行时的状态 • 就绪状态:进程分配到必要的资源,还没获得在CPU上执行的状态 • 阻塞状态(等待状态):进程的执行由于本身不具备运行条件而受到阻塞,处于暂停状态
Running 等待事件 (系统服务请求,如请求I/O)) 被调度或分派 时间片 用完 Ready Blocked 事件发生
进程的状态 细分的进程调度状态 • 挂起:强迫进程释放分配到的资源,将进程调出到外存 • 活动:未被挂起的就绪和阻塞状态称为活动就绪和活动阻塞 • 静止:被挂起的就绪和阻塞状态称为静止就绪和静止阻塞
wakeup (唤醒) 事件发生 Readya Blockeda 时间片完 schoduler 等待事件sleep 被调度 解挂active Running 挂起suspend 挂起suspend 解挂active 挂起suspend Readys Blockeds 事件发生 图:具有挂起功能的进程状态变化 wakeup (唤醒)
进程的状态转换: 三状态进程模型
进程控制块(PCB, process control block) 进程的物理结构 • 程序:描述进程要完成的功能 • 数据集合:包含程序运行所需的数据和工作区 • 进程控制块(PCB):包含进程的描述信息和控制信息,是进程动态特性的反映 程序和数据集合是进程的实体 进程控制块是进程存在的唯一标志 进程控制块是由OS维护的用来记录进程相关信息的一块内存。
进程控制块的内容 • 进程标识符: • 进程标识符(process ID)(内部标识符):唯一,通常是一个整数; • 进程名(外部标识符) :不唯一,由字母数字组成; • 位置信息:指出进程的程序和数据在内存和外存中的物理位置 • 现场信息:寄存器值(通用、程序计数器PC、状态PSW,地址包括栈指针) • 状态信息:进程现行状态 • 进程优先级:进程使用CPU的优先级别 • 资源清单:已分配到的资源等 • 同步与互斥机构 • 进程通讯机制 • 队列指针 • 家族联系 • 资源占用信息:虚拟地址空间的现状、打开文件列表
PCB的组织方式 • 顺序表:将所有PCB连续存放在内存。要经常扫描整个表 • 索引表:同一状态的PCB建立一个index表(由index指向PCB),多个状态对应多个不同的index表 • 各状态形成不同的索引表:就绪索引表、阻塞索引表 • 链表:同一状态的进程的PCB成一链表,多个状态对应多个不同的链表 • 各状态的形成不同的链表:就绪链表、阻塞链表
进程控制 进程控制的功能 完成进程状态的转换。 原语(primitive):由若干条指令构成的“原子操作(atomic operation)”过程,作为一个整体而不可分割--要么全都完成,要么全都不做。许多系统调用就是原语。
2.3 进程调度 作业状态及其转换 • 提交状态 • 后备状态:作业的全部信息已输入到磁盘的专用区(后备作业区)中,等待运行 • 执行状态:被作业调度程序选中,分配了必要资源,建立了PCB,进入进程的就绪状态,等待运行 • 完成状态:作业完成任务,释放资源
调度的层次 作业从提交到完成,要经历三级调度 • 作业调度(高级调度):选择作业,调入内存,分配资源建立进程,将PCB插入就绪进程队列 • 进程调度(低级调度):将CPU分配给进程,进行进程间切换,运行被调度进程 • 中级调度:进程映象在内存和盘交换区间的对换操作。防止死锁。
进程调度算法 进程调度方式 按占用处理器的方式,进程调度有两种方式: • 非剥夺抢占方式:一旦进程占用CPU就一直运行,直到终止或阻塞 • 剥夺抢占方式:系统强行剥夺已分配给现运行进程的CPU,使其进入就绪进程队列
调度算法性能标准 • 设计目标:目标不同,系统的要求不同 • CPU利用率: • 吞吐量:系统在单位时间内完成的作业数目 • 周转时间:从作业提交到完成的时间间隔 • 等待时间:进程在就绪进程队列中的等待时间,通常用来衡量调度程序的性能 • 响应时间:从向系统发出请求到系统首次开始响应的时间间隔 • 资源利用率:最大限度地使各种资源并行操作 • 合理的系统开销
进程调度算法 先来先服务算法(FCFS) • 按先进先出组织就绪状态的进程队列 • 总是把CPU分配给就绪状态的进程队列的队首进程 • 最简单的进程调度算法 • 属于非剥夺抢占方式
例:进程P1,P2,P3,它们的CPU运行时间为3,3,24个单位时间例:进程P1,P2,P3,它们的CPU运行时间为3,3,24个单位时间 (1)P3,P1,P2顺序进入就绪进程队列,几乎同时到达 平均周转时间=(24+27+30)/3=27 (2)P1,P2,P3顺序进入就绪进程队列,几乎同时到达 平均周转时间=(3+6+30)/3=13 FCFS特点: 仅考虑作业提交时间,未考虑系统资源使用率
进程调度算法 短CPU运行期优先算法(SCBF) • 要求就绪状态的进程队列中每个进程有下一个CPU运行期的时间值 • 把CPU分配给就绪状态的进程队列中下一个CPU运行期最短的进程 • 短者优先的原则 优点:等待时间最小,系统吞吐量高 缺点:已知进程的CPU运行时间,很难实现
例:进程P1,P2,P3,P4,它们的CPU运行时间为6,3,8,7个单位时间,P3,P1,P2,P4顺序进入就绪进程队列,几乎同时到达例:进程P1,P2,P3,P4,它们的CPU运行时间为6,3,8,7个单位时间,P3,P1,P2,P4顺序进入就绪进程队列,几乎同时到达 FCFS算法:平均周转时间=(8+14+17+24)/4=15.75 SCBF算法:平均周转时间=(3+9+16+24)/4=13
进程调度算法 优先权调度算法 • 系统自动按一定原则为每个进程规定一个调度优先权 • 把CPU分配给就绪状态的进程队列具有最高优先权的进程 • 常用的调度算法 确定优先权的方法: 静态优先权法 动态优先权法
静态优先权法 进程创建时确定其优先权,运行期间不改变 • 按进程类型确定 • 按作业要求的资源类型和数量确定 • 按作业提交的时间顺序确定 • 按用户类型和要求确定 优点:简单易实现,系统开销小 缺点:未能反映进程的动态性 动态优先权法 进程创建时赋一个优先权初值,运行期间动态调整其权值 特点:防止一个进程垄断或长期等待CPU
时间片轮转算法 简单轮转法 • 就绪状态的所有进程按FCFS组成队列 • 首先CPU分给队首的进程,规定一个时间片 • 就绪队列中的所有进程轮流使用CPU T=Nq N就绪队列中进程数,T为系统响应时间,时间片为q 多队列轮转法 • 常用双就绪状态进程队列轮转法 • 首先对前台就绪进程队列以时间片轮转法调度,当前台就绪进程队列为空时,才对后台就绪进程队列按FCFS算法调度
多级反馈队列调度算法 • 按调度级别设置多个就绪进程队列 • 按级别划分时间片 • 各级就绪进程队列按FIFO组织,FCFS调度 • 最后一级按循环轮转方式组织调度
2.4 进程间的同步与互斥 • 进程间的制约关系 • 间接制约:进行竞争--独占分配到的部分或全部共享资源,“互斥” • 直接制约:进行协作--等待来自其他进程的信息,“同步” 临界资源 系统中一次仅允许一个进程使用的一类资源。 打印机,卡片输入机,磁带机、共享变量等。 互斥:多个进程不能同时使用同一个资源; 死锁:多个进程互不相让,都得不到足够的资源; 饥饿:一个进程一直得不到资源(其他进程可能轮流占用 资源)
例:民航售票系统,n个售票处 • /*Process Pi ,i=1,2,...,n*/ • ….. • /*按订票要求找到共享数据x[k]*/ • /*x[k]存放某月某日某次航班的现有票数*/ • R=x[k]; /*现有票数*/ • if(R>=1){ • R--; • x[k]=R; • 输出一张机票; • } • else • 显示“票已售完”; 共享变量的修改冲突
临界区: 访问临界资源的程序段。 同类临界区: 对同一临界资源进行操作的程序段。 临界区的访问过程 临界区
临界区(critical section):进程中访问临界资源的一段代码。 • 进入区(entry section):在进入临界区之前,检查可否进入临界区的一段代码。 • 退出区(exit section) • 剩余区(remainder section):代码中的其余部分。
互斥应遵循的准则 • 空闲则入:其他进程均不处于临界区; • 忙则等待:已有进程处于其临界区; • 有限等待:等待进入临界区的进程不能"死等"; • 让权等待:不能进入临界区的进程,应释放CPU(如转换到阻塞状态)
互斥算法 进程互斥的软件方法 算法1:单标志 • 有两个进程Pi, Pj,其中的Pi • 设立一个公用整型变量 turn:描述允许进入临界区的进程标识
缺点:强制轮流进入临界区,没有考虑进程的实际需要。容易造成资源利用不充分:在Pi出让临界区之后,Pj使用临界区之前,Pi不可能再次使用临界区;缺点:强制轮流进入临界区,没有考虑进程的实际需要。容易造成资源利用不充分:在Pi出让临界区之后,Pj使用临界区之前,Pi不可能再次使用临界区;
算法2:双标志 • 设立一个标志数组flag[]:描述进程是否要求进入临界区或已在临界区,初值均为FALSE • turn=j;描述可进入的进程(同时修改标志时) • 在进入区先修改、后检查、后修改者等待 • int flag[2]={0,0}; • int turn=0; • /*进程pi的结构*/ • while(1){ • flag[i]=1; • while(flag[j]){ • if(turn==j){ • flag[i]=0; • while(turn==j); • flag[i]=1; • } • /*进入临界区*/ • critical section • /*退出临界区]*/ • turn=j; • flag[i]=0; • remainder section • }
进程互斥的锁操作方法 • 每一类临界资源设置一把锁lock。 • lock表示资源的两种状态:TRUE表示正被占用(锁关状态);FALSE表示空闲(锁开状态) 加锁操作 执行临界区程序 开锁操作
锁操作方法 用开、关中断实现锁操作 关中断 • 不能实现所有的同类临界区互斥; • 临界区太长时,降低了中断响应速度; • 扩大了互斥范围; • 加锁时CPU不断测试,处于忙等待。 执行临界区程序 开中断 优点:简单、可靠 缺点:
信号量(semaphore) 信号量表示临界资源的实体,是一个数据结构,其值仅能由P、V操作来改变。 阻塞等待信号量数据结构: typedef struct{ int value; /*信号量的值*/ PCB *ptr_of_semque; } semaphore ; PCB:进程控制块的数据类型 ptr_of_semque:指向等待使用该信号量的进程队列的队首
信号量初始化: • Value:指定一个非负整数值,表示空闲资源总数--若为非负值表示当前的空闲资源数,若为负值其绝对值表示当前等待临界区的进程数 • ptr_of_semque:初值为空 • P原语wait(s) extern PCB *curproc; void p(s) semaphore *s; { s->value--; if(s->value<0){ Insert(curproc,s-> ptr_of_semque); Block(curproc); } }
V原语signal(s) V原语通常唤醒进程等待队列中的头一个进程 void V(s) semaphore *s; { PCB *pcb_ptr; s->value++; if(s->value<=0){ pcb_ptr=Remove(s-> prt_of_semque); Wakeup(pcb_ptr); /*进程状态置为活动就绪*/ } }
利用信号量实现互斥 • 为临界资源设置一个互斥信号量mutex(MUTual Exclusion),其初值为1;在每个进程中将临界区代码置于P(mutex)和V(mutex)原语之间 • 必须成对使用P和V原语,P、V原语不能次序错误、重复或遗漏
信号量实现互斥模型: semaphore mutex={1,NULL}; cobegin program pi { while(1){ P(&mutex); critical section for pi; /*进程pi临界区*/ V(&mutex); remainder section for pi; } } coend
例:民航售票系统,n个售票处 • semaphore mutex={1,NULL}; • cobegin • program pi • { • ……… • P(&mutex); • R=x[k]; /*现有票数*/ • if(R>=1){ • R--; • x[k]=R; • V(&mutex); • 输出一张机票; • } else{ V(&mutex); 显示“票已售完”; } } coend 解决共享变量的修改冲突
利用信号量实现同步 semaphore proceed1={0,NULL}; cobegin 进程p1 ……… P(& proceed1); ……… 进程p2 ……… V(& proceed1); ………. coend 设置一个同步信号量proceed1,其初值为0
例:一辆公共汽车上,司机和售票员进程的同步例:一辆公共汽车上,司机和售票员进程的同步 • semaphore drive_sem={0,NULL}; • semaphore conductor_sem={0,NULL}; • cobegin • program drive • { • while(1){ • driving; /*正常行车*/ • stopping; • V(&conductor_sem); /*唤醒开门*/ • P(&drive_sem); /*等待关门*/ • start a car; • } • }