前趋图和程序执行
前驱图
有向无循环图,记为DAG(Direct Acyclic Graph),用于描述进程之间执行的先后顺序。
进程间前趋关系用→表示,若进程Pi Pj存在Pi → Pj,表示在Pj开始执行前Pi必须完成。
直接前驱:此时Pi是Pj的直接前驱
直接后继:此时Pj是Pi的直接后继
初始结点:没有前驱的节点
终止结点:没有后继的节点
结点的重量:用于表示该节点所含有的程序量或程序的执行时间
程序顺序执行
程序的顺序执行就是仅当前一操作(程序段)执行完后,才能执行后继操作。
程序顺序执行特征:
1.顺序性
2.封闭性
3.可在现性
程序并发执行(如果是并发的那么就没有前驱后继关系)
例:一个作业分为输入程序(Ii),计算程序(Ci),打印程序(Pi)三部分,存在前趋关系Ii → Ci → Pi,只能顺序执行。但c1和I2可以并发执行。
程序并发执行特征:
1. 间断性:当计算完成了C1后,输入程序I2尚未完成,计算程序C2必须暂停运行。
2. 失去封闭性:并发运行程序时,系统中资源被共享,资源的状态由这些程序来改变。
3. 不可再现性:程序并发执行时,由于失去了封闭性,导致其又失去了可再现性。
进程的描述
引入进程的目的: 为了能使程序并发执行,并且可以对并发执行的程序加以描述和控制,引入了“进程”的概念。
引入进程控制块的目的: 为了使参与并发执行的程序都能独立地运行,在操作系统中必须为之配置一个专门的数据结构——进程控制块(PCB)。
进程实体:进程实体由程序段、相关的数据段和PCB构成
进程:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
进程的特征
1.动态性(进程与程序最本质的区别)
2.并发性
3.独立性
4.异步性
进程三种基本状态
就绪:程序只要获得CPU使用权,便可执行
执行:程序已经获得CPU,正在被执行
阻塞:正在执行的进程由于发生某事件,无法继续执行
三态转换(三态图)
五态(三态+创建+终止)
创建:
1. 申请空白PCB
2. 向PCB中填写控制管理进程信息
3. 分配运行时所需的资源
4. 插入就绪队列
终止:
等待操作系统善后处理,最后将PCB清零,并将PCB返还系统。
(五态图)
七态(五态中就绪,阻塞分为活动和静止状态;引入了挂起,激活)
引入挂起(把内存中的进程放到外存中去)
挂起操作引入原因:
1.终端用户希望暂停;
2.父进程请求,希望挂起某个子进程;
3.系统负荷过重,挂起一些不重要进程;
4.操作系统为方便检查资源使用情况或进行记账;
(进程5状态转换图)
进程管理中的数据结构
进程控制块PCB
PCB的作用:
1.作为独立运行基本单位的标志
2.能实现间断性运行方式
3.提供进程管理所需的信息
4.提供进程调度所需的信息
5.实现与其他进程的同步与通信
PCB中的信息:
1.进程标识符(对应着PCB作用中的作为独立运行基本单位的标志)
外部标识符:字母数字构成
内部标识符:唯一数字标识
2.处理机状态(对应着PCB作用中的能实现间断性运行方式)
(1)通用寄存器(R1,R2,...):用户程序可以访问的,用于暂存信息的用户可视寄存器。
(2)指令计数器(PC):存放了要访问的下一条指令的地址。
(3)程序状态字(PSW):状态信息,如条件码、执行方式、中断屏蔽标志等。
(4)用户栈指针(SP):存放过程或系统调用参数及调用地址。
3.进程调度信息(对应着PCB作用中的提供进程调度所需的信息)
(1)进程状态(就绪?阻塞?挂起?)(进程调度的依据)
(2)进程优先级
(3)进程已等待CPU时间总和,已执行时间总和。
(4)进程由执行态转为阻塞态所等待发生的原因(阻塞原因)
4.进程控制信息(对应着PCB作用中的提供进程管理所需的信息)
(1)程序和数据地址,进程实体中程序和数据的内存或外存地址。
(2)进程同步与通信机制。
(3)资源清单(全部资源 + 已分配)。
(4)链接指针。指出下个进程PCB的首地址。
PCB的组织方式
1.线性方式
系统中所有PCB都在一张线性表中。实现简单、开销小,每次查找需要扫描整张表,适合进程数目不多的系统。
2.链接方式
把具有相同状态进程的 PCB通过链接字链成一个队列
3.索引方式
根据进程的不同状态,建立几张索引表
进程控制
创建 与 终止
阻塞 与 唤醒
挂起 与 激活
OS内核
通常将一些与硬件紧密相关的模块(如中断处理程序等)、各种常用设备的驱动程序以及运行频率较高的模块(如时钟管理、进程调度和许多模块所公用的基本操作),都安排在紧靠硬件的软件层次中,将它们常驻内存,被称为OS内核。
处理机的执行状态:
系统态(Kernel Mode):运行OS程序(处于系统态执行中的进程能访问所有的寄存器和存储器,且所占有的处理机是不允许被抢占的)
用户态(User Mode):运行用户程序(处于用户态执行中的进程能访问的寄存器和存储器受限,且所占有的处理机是可被抢占的)
OS内核两大功能:
支撑功能:(核心功能)
中断处理
时钟管理
原语操作:由若干条指令组成,用于完成一定的功能,不允许中断,不允许并发执行。
资源管理功能:(基本功能)
进程管理
存储器管理
设备管理
进程的创建:
1. 进程图
父进程、子进程(树)
2. 引起创建进程事件
用户登录,作业调度,提供服务,应用要求。
两种进程创建:
由系统程序模块统一创建:由系统统一创建的进程之间的关系是平等的,它们之间一般不存在资源继承关系。(例如:作业调度)
由父进程创建:用进程树来描述进程之间的关系,属于某一家族的进程可以继承其父进程所拥有的部分或全部资源。
创建进程过程:
(1)申请空白PCB,并从PCB集合中索取一个空白PCB
(2)为新进程分配其运行所需的资源
(3)初始化PCB
(4)插入就绪队列
进程的终止:
1.正常结束2.异常结束:越界错,保护错,非法指令,特权指令错,运行超时,等待超时,算术运算错,I/O故障。
3.外界干预
进程终止过程:
(1)根据标志符检索PCB,读出进程状态
(2)若状态 = 执行态,立即终止,置调度标志
(3)若含子进程,全部终止,防止不可控
(4)拥有资源归还父进程或系统
(5)PCB从所在队列中移出
进程的阻塞和唤醒
1.引起阻塞和唤醒的事件
(1) 向系统请求共享资源失败
(2) 等待某种操作完成
(3) 新数据尚未到达
(4) 等待新任务到达
2.进程阻塞过程
- 处于执行态,进程应立即停止执行
- PCB状态: 执行→阻塞
- PCB插入到阻塞队列中
- 调度程序重新调度,分配处理机
3.进程唤醒过程
- 被阻塞进程移出阻塞队列
- PCB状态:阻塞→就绪
- PCB插入到就绪队列中
进程的挂起与激活
1. 进程的挂起
活动阻塞→静止阻塞,活动就绪→静止就绪, 执行→静止就绪
进程内容从内存暂时调出到外存。
2. 进程的激活
进程内容从外存调入到内存
静止阻塞→活动阻塞,静止就绪→活动就绪
进程同步
进程同步的任务:
对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定规则共享系统资源,并能很好相互合作,从而使程序的执行具有可再现性。
1.两种形式的制约关系
1)间接相互制约关系
2)直接相互制约关系
2.临界资源(被多个进程所共享的资源)
3.临界区(访问临界资源的那片代码称为临界区)
访问临界资源的循环进程可以表示为:
while(ture){
进入区(在临界区前加上一段用于检查的代码)
临界区
退出区(在临界区后加上一段用于恢复临界区未被访问的标志的代码)
剩余区
}
4.同步机制应遵循的规则
(1)空闲让进: 当资源空闲时,应当允许访问资源的进程进入临界区
(2)忙则等待: 当资源被占用时,应使申请访问该资源的进程等待,等待使用者归还资源
(3)有限等待: 系统应保证等待的进程能在有限的时间内获得资源,继续执行,以防止无限等待浪费该进程已占用的资源。防止”死等”
(4)让权等待: 在进程等待资源时,从执行态转为阻塞态,应当让出CPU的使用权。系统将把CPU分配给其它进程使用,以提高系统效率。防止”忙等”
硬件同步机制(实现进程互斥)
锁操作的特点: 实现了进程互斥访问临界资源;不遵循让权等待原则——忙等。
1.关中断
保证对锁的检测和关锁操作的连续性和完整性,就有效的保证了互斥。
2. TS指令实现互斥(Test-and-Set)
boolean TS(boolean *lock){ boolean old; old = *lock; *lock = TRUE;//表示该资源正在被使用 return old; }
利用TS指令实现进程互斥
do{ ... while TS(&lock);//进入 critical section; lock = FALSE;//退出 remainder section; }while(TRUE);
3. Swap指令实现互斥
swap(boolean *a, boolean *b) { boolean temp; temp=*a; *a=*b; *b=temp;//交换内容 }
利用Swap指令实现进程互斥
do{ key = TRUE; do{ swap(&lock,&key); }while(key != FALSE); 临界区操作; lock = FALSE; ... }while(TRUE);
信号量机制(解决进程的同步与互斥的工具)
1. 整型信号量
S是与临界区内所使用的共享资源有关的信号量。仅能通过两个原子操作wait(s)和signal(s)来访问。这两个操作分别被称作P,V操作
wait(S){ while(S <= 0) ; S --; } signal(S){ S ++; }
wait(s)和signal(s)是原子操作,所以在执行时是不可以中断的,所以缺点就是:未遵循“让权等待”,长期“忙等”。
2. 记录型信号量
采取“让权等待”策略后,又出现多个进程等待访问同一临界资源的情况。信号量机制中增加进程链表指针,链接等待进程。
typedef struct{ int value; struct process_control_block *list; }semaphore; //记录型信号量的P、V操作 wait(semaphore *S){ S -> value --; if(S->value<0) block(S->list); } signal(semaphore *S){ S -> value ++; if(S->value<=0) wakeup(S->list); }
P原语操作:
- S->value-1
- 如果S->value-1以后仍大于等于零,则进程继续进行
- 如果S->value-1以后小于零,则将该进程阻塞以后插入阻塞队列,然后转进程调度
V原语操作:
- S->value +1
- 如果S->value +1结果大于零,则进程继续
- 如果S->value +1结果小于等于零,则将S-> list中第一个等待该资源的进程唤醒
P,V操作都是原语二者必须成对出现。
3. AND型信号量(引入原因:一个进程需要先获得 两个或更多的资源后,方能 执行其任务。)
假设进程A和B,他们要求访问共享数据D和E,为共享数据设置互斥信号量Dmutex和Emutex,初值为1。
process A: wait(Dmutex); wait(Emutex); process B: wait(Emutex); wait(Dmutex);
在这个交替执行过程中容易发生死锁。
这时就需要用到AND同步机制。它的的基本思想是:将对多个信号量的逐个申请改为一次,用一个原子操作完成;进程要么一次获得所有的资源,要么一个也申请不到。
4.信号量集
引入原因:
在记录型信号量中每次对S仅能施以加1或减1操作,即每次只能获得或释放一个单位的临界资源。
①一次需要N个某类临界资源时; ②资源数量低于某一下限值时,便不予分配;
可对AND信号量机制加以扩充,形成一般化的“信号量集”机制。
对应的P,V操作:(Si – 资源信号量;ti – 每类资源分配给进程的下限值;di – 进程对资源的需求值)
SP(S1,t1,d1,...,Sn,tn,dn);
SV(S1,d1,...,Sn,dn);
信号量集中所出现的特殊情况:
(1) Swait(S,d,d)。信号量集中只有一个信号量S,每次申请d个资源,现有资源数少于d,不予分配。
(2) Swait(S,1,1)。蜕化为记录型信号量(S>1)或互斥信号量(S=1)。
(3) Swait(S,1,0)。S≥1时,允许多个进程进入某特定区域;当S变为0后,阻止任何进程进入特定区。相当于一个可控开关。
信号量的应用
利用信号量实现进程互斥与同步:
多个进程互斥访问临界资源,为资源设置互斥信号量mutex,初值为1,各进程访问该资源的临界区置于wait(mutex)和signal(mutex)之间。
mutex=1时:表示两个进程都未进入需要互斥的临界区;
mutex=0时:表示有一个进程进入临界区运行;
mutex=-1时:表示一个进程正在临界区运行,另一个进程因等待而阻塞在信号量队列中,需被当前已在临界区运行的进程退出时唤醒。
P、V成对出现,先P后V。
semaphore mutex = 1; PA{ while(1){ wait(mutex); 临界区; signal(mutex); 剩余区; } } PB{ while(1){ wait(mutex); 临界区; signal(mutex); 剩余区; } }
利用信号量实现前趋关系:
进程P1执行语句块p1,进程P2执行语句块p2,存在前趋关系。
经典进程同步问题
生产者-消费者问题
问题描述:生产者生产的产品放入缓冲池内; 消费者从缓冲池内取走产品消费; 消费者消费后的空白缓冲区供生产者使用。
规则:有空的buffer时生产者便可将产品送入缓冲池;有满的buffer时消费者可从中取走产品;消费者与生产者互斥地访问缓冲区。
消费者进程与生产者进程间的关系:
- 生产者生产产品后消费者消费;
- 消费者消费后的空白缓冲块由生产者存放产品;
- 两个进程在使用缓冲区时的关系为互斥关系。
使用到的信号量:
(1)mutex – 互斥信号量,各进程互斥访问缓冲区,初值1
(2)full – 资源信号量,满缓冲区个数,初值0
(3)empty – 资源信号量,空缓冲区个数,初值n
生产者进程:
void producer() { while(true) { 生产一个产品; P(empty); P(mutex); buffer[in] =nextp; in=(in+1)% n; V(mutex); V(full); } }
消费者进程:
void consumer() { while(true) { P(full); P(mutex); nextc = buffer[out]; out = (out+1)%n; V(mutex); V(empty); 消费该产品; } }
所需要注意的事项:
(1)对各信号量的P、V操作必须成对出现
互斥信号量:P、V操作在同一进程成对出现
资源信号量:P、V操作处于不同进程成对出现
(2)多个P操作不能颠倒,先执行对资源信号量的P操作,再执行对互斥信号量的P操作,V操作的次序无关紧要。
哲学家进餐问题
问题描述:五位哲学家共用一张圆桌,分别坐在周围五张椅子上,在圆桌上有五只碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用左右靠近他的两只筷子,只有拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。
进程间的关系:相邻座位的两个哲学家在使用筷子时的关系为互斥关系。
semaphore chopstick[5] = {1,1,1,1,1}; do{ wait(chopstick[i]); wait(chopstick[(i+1)%5]); … //eat … signal(chopstick[i]); signal(chopstick[(i+1)%5]); … //think … }while(TRUE);
哲学家进餐解决死锁办法:
(1)至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用完时释放出他所使用过的两只筷子,从而使更多哲学家能够进餐。
semaphore chopstick[5] = {1,1,1,1,1}; semaphore count=4; do{ wait(count); wait(chopstick[i]); wait(chopstick[(i+1)%5]); eat(); signal(chopstick[i]); signal(chopstick[(i+1)%5]); signal(count); think(); }while(TRUE);
(2) 仅当哲学家的左右两只筷子均可用是,才允许他拿起筷子进餐。
semaphore chopstick[5] = {1,1,1,1,1}; do{ Swait(chopstick[i], chopstick[(i+1)%5]); eat(); Ssignal(chopstick[i], chopstick[(i+1)%5]); think(); }while(TRUE);
(3) 规定奇数号哲学家先拿他左边的筷子,然后再去拿他右边的筷子;而偶数号哲学家则正好相反。
semaphore chopstick[5] = {1,1,1,1,1}; do{ if(i%2==1) { P(chopstick[i]); P(chopstick[(i+1)%5]); eat(); V(chopstick[i]); V(chopstick[(i+1)%5]); think(); } else{ P(chopstick[(i+1)%5]); P(chopstick[i]); eat(); V(chopstick[i]); V(chopstick[(i+1)%5]); think(); } }while(TRUE);
读者-写者问题
某数据库有多个写进程、多个读进程,它们之间读、写操作的互斥要求是:写进程运行时,其他读、写进程不能对数据库进行操作,且读、写进程不能同时对数据库进行操作。读进程之间不互斥,可以同时读数据库。
一个数据记录缓冲区,有多个进程进行读操作,另一些进程进行写操作
(Reader) (Writer)
读写策略:
(1)允许多个进程同时进行读操作
(2)不允许多于一个进程进行写操作
(3)不允许读写操作同时进行
- Wmutex——写进程与写进程以及读进程互斥地访问数据文件,初值为1
- Readcount——读者数量,初值为0
- Rmutex——读进程互斥地访问共享变量Readcount,初值为1
读
void reader(){ do{ P(rmutex); if(readcount == 0) P(wmutex); readcount++; V(rmutex); ... perform read operation; ... P(rmutex); readcount--; if(readcount == 0) V(wmutex); V(rmutex); }while(TRUE); }
写
void writer(){ do{ P(wmutex);//获取对数据库的操作 perform write operation; V(wmutex);//释放对数据库的操作 }while(TRUE); }
进程通信
进程之间的信息交换称为进程通信
进程通信按通信内容可分为:
- 控制信息的传送
- 大批量数据传送
把进程间控制信息的交换称为低级通信;
把进程间大批量数据的交换称为高级通信。
进程通信的类型
1.共享存储器系统
(1)基于共享数据结构的通信方式
(2)基于共享存储区的通信方式
2.管道通信系统
连接读写进程的一个特殊文件, 发送进程以字符流形式把大量数据送入管道,接收进程从管道中接收数据。
实质:是一个共享文件,基本上可借助于文件系统的机制实现,包括(管道)文件的创建和读写。
提供三方面的协调能力:互斥,同步,确定对方的存在。
3.消息传递系统
在消息传递系统中,进程间的数据交换,是以格式化的消息为单位的;程序员直接利用系统提供的一组通信命令(原语)进行通信。
实现方式的不同,而分成:
(1)直接通信方式:进程-进程
(2)间接通信方式:进程-信箱-进程
4、客户机-服务器系统(网络通信)
(1) socket套接字(数据结构)
(2) 远程过程调用和远程方法调用(通信协议)
线程
操作系统中引入线程则是为了减少程序并发执行时所付出的时空开销,使操作系统具有更好的并发性。
程序并发执行的时空开销:
(1) 创建进程。分配资源,建立PCB。
(2) 撤销进程。资源回收,撤销PCB。
(3)进程切换。保留当前进程环境,设置新选进程环境。
由于进程是一个资源的拥有者,因而在进程的创建、撤销和切换中,系统必须为之付出较大的时空开销。
也正是如此,在系统中所设置的进程数目不宜过多,进程的切换的频率也不宜过高,这就限制了进程并发程度的进一步提高。
线程的概念
线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制流),这就是多线程。
线程运行在进程的上下文中,并使用进程的资源和环境。
系统调度的基本单位是线程而不是进程,每当创建一个进程时,至少要同时为该进程创建一个线程,否则该进程无法被调度执行。
进程
线程
调度基本单位
传统OS调度基本单位
引入线程OS调度基本单位
并发性
不同进程并发
不同进程中线程并发,具有更好并发性。采用多线程执行相似任务。
拥有资源
拥有分配的全部资源
拥有少量必备资源,共享所属进程的全部资源
独立性
好
差
系统开销
大
小
支持多处理机系统
不支持
支持。多个线程分配到多个处理机可加速任务处理。
1.线程运行状态:执行,就绪,阻塞。
2.线程控制块TCB:线程标识符;一组寄存器;线程运行状态;优先级;线程专有存储区;信号屏蔽;堆栈指针
3.多线程OS中的进程属性:
(1)进程是一个可拥有资源的基本单位。
(2)多个线程可以并发执行。
(3)进程已不是可执行的实体。