《计算机操作系统》第四版,逢考必过!!!
2.1 前趋图和程序执行
2.1.1 前趋图
前趋图(Precedence Graph)是一个
有向无循环图
,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系。
→={(Pi, Pj)|Pi must complete before Pj may start}, 如果(Pi, Pj)∈→,可写成Pi→Pj,称Pi是Pj的直接前趋,而称Pj是Pi的直接后继。把没有前趋的结点称为初始结点(Initial Node),把没有后继的结点称为终止结点(Final Node)。每个结点还具有一个重量(Weight),用于表示该结点所含有的程序量或结点的执行时间。
2.1.2 程序顺序执行
1. 程序的顺序执行
2. 程序顺序执行时的特征
(1) 顺序性
(2) 封闭性
(3) 可再现性
2.1.3 程序的并发执行及其特征
只有不存在前驱关系的查询之间才可能并发执行
2. 程序并发执行时的特征
- 间断性
- 失去封闭性
- 不可再现性
2.2 进程的描述
2.2.1 进程的定义和特征
1. 定义
为了使参与并发执行的每个程序(含数据)能够独立运行,在操作系统中必须为之配置一个专门的数结构,成为
进程控制块(PCB)
。系统利用PCB来
描述进程的基本情况和活动过程,进而控制和管理进程
。由
程序段、相关数据段和PCB三部分便构成了进程实体
(进程映像),简称为进程。
创建进程即创建PCB,撤销进程即撤销PCB
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
2. 特征
- 动态性 2) 并发性(程序不能并发执行,而进程实体可以) 3) 独立性 4) 异步性
2.2.2 进程的基本状态及转换
1. 进程的三种基本状态
-
就绪(Ready)状态
进程已处于准备好运行状态,即已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行。多个就绪状态的进程按一定的策略排成就绪队列。 -
执行(Running)状态
进程已获得CPU,其程序正在执行的状态。任意时刻,单处理机系统只有一个进程处于执行状态,多处理机系统有多个执行状态的进程。 -
阻塞(Block)状态
正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)暂时无法继续执行时的状态,即进程的执行收到阻塞。引起进程调度,将处理机分配给另一个就绪进程,而让受阻进程出去暂停状态,即阻塞状态或等待状态或封锁状态。处于阻塞状态的进程排成一个队列,即阻塞队列。
2. 三种基本状态的转换
3. 创建状态和终止状态
2.2.3 挂起操作和进程状态的转换
1. 挂起操作的引入
-
终端用户的请求。
-
父进程请求。
-
负荷调节的需要。
-
操作系统的需要。
2. 引入挂起原语操作后进程状态的转换
- 活动就绪→静止就绪。
- 活动阻塞→静止阻塞。
- 静止就绪→活动就绪。
- 静止阻塞→活动阻塞。
3. 引入挂起操作后五个进程状态的转换
创建⇒静止就绪:考虑到系统当前资源状况和性能的要求,不分配给新建进程所需的资源,主要是主存,相应的系统将进程状态转为静止就绪状态,被放在外存,不参与调度。
2.2.4 进程管理中的数据结构
1. 用于管理控制的数据结构
计算机系统中,对
每一个资源和每个进程都设置了一个数据结构,用于表征其实体
,称为
资源信息表或进程信息表
,其中包含了资源或进程的标识、描述、状态等信息及一批指针。将数据结构分为四类:内存表、设备表、文件表、进程表。
2. 进程控制块的作用
PCB记录操作系统所需的,用于描述进程的当前情况以及管理进程运行的全部信息
,是操作系统中最重要的记录型数据结构。使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。
作用:
1)
作为独立运行基本单位的标志
系统通过PCB感知进程的存在;PCB已成为进程存在于系统的唯一标志
2)
能实现间断性运行方式
系统将CPU现场信息保存在被中断进程的PCB中,供该进程再次调度执行时恢复CPU现场时使用
传统意义上的静态程序,不具有保护或保存自己运行现场的手段,无法保证其运行结果的可再现
3)
提供进程管理所需要的信息
4)
提供进程调度所需要的信息
5)
实现与其他进程的同步与通信
采用信号量机制,要求在每个进程都设置有相应的用于同步的信号量。
3. 进程控制块中的信息
-
进程标识符:唯一标识一个进程(外部标识符、内部标识符)
-
处理机状态:由处理机的各种存储器中的内容组成
① 通用寄存器,又称为用户可视寄存器,它们是用户程序可以访问的,用于暂存信息, 在大多数处理机中,有 8~32 个通用寄存器,在RISC结构的计算机中可超过 100 个;
② 指令计数器,其中存放了要访问的下一条指令的地址;
③ 程序状态字PSW,其中含有状态信息,如条件码、执行方式、 中断屏蔽标志等;
④ 用户栈指针, 指每个用户进程都有一个或若干个与之相关的系统栈,用于存放过程和系统调用参数及调用地址。 -
进程调度信息
① 进程状态,指明进程的当前状态, 作为进程调度和对换时的依据;
② 进程优先级,用于描述进程使用处理机的优先级别的一个整数, 优先级高的进程应优先获得处理机;
③ 进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、 进程已执行的时间总和等;
④ 事件,是指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。 -
进程控制信息
① 程序和数据的地址, 是指进程的程序和数据所在的内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据;
② 进程同步和通信机制,指实现进程同步和进程通信时必需的机制, 如消息队列指针、信号量等,它们可能全部或部分地放在PCB中;
③ 资源清单,是一张列出了除CPU以外的、进程所需的全部资源及已经分配到该进程的资源的清单;
④ 链接指针, 它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。
4. 进程控制块的组织方式
- 线性方式
- 链接方式
- 索引方式
2.3 进程控制
2.3.1 操作系统的内核
将一些于
硬件紧密相关的模块、各种常用设备的驱动程序以及运行频率较高的模块
,都安排在紧靠硬件的软件层次中,它们
常驻内存
,被称为OS的
内核
。
处理机的执行状态分为
-
系统态(内核态,管态)
-
用户态(目态)
两大方面的功能
- 支撑功能:中断处理、时钟管理、原语操作
- 资源管理功能:进程管理、存储器管理、设备管理
2.3.2 进程的创建
1. 进程的层次结构
一个进程创建另一个进程,创建进程的进程为父进程。子进程可继承父进程拥有的所有资源。
Windows中不存在层次结构。如果一个进程创建另外的进程获得了一个句柄,其作用相当于一个令牌,可以用来控制被创建的进程。但是句柄可以被传递,获得了句柄的进程就有控制其他进程的权力。是获得句柄与否,控制与被控制的简单关系。
2. 进程图(Process Graph)
有向树
3. 引起创建进程的事件
- 用户登录。
- 作业调度。
- 提供服务。
- 应用请求。
4. 进程的创建(Creation of Progress)
(1) 申请空白PCB。
(2) 为新进程分配资源。
(3) 初始化进程控制块。
(4) 将新进程插入就绪队列,如果进程就绪队列能够接纳新进程, 便将新进程插入就绪队列。
2.3.3 进程的终止
1. 引起进程终止(Termination of Process)的事件
- 正常结束
- 异常结束
- 外界干预
2. 进程的终止过程
(1) 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态。
(2) 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度。
(3) 若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。
(4) 将被终止进程所拥有的全部资源,或者归还给其父进程, 或者归还给系统。
(5) 将被终止进程(它的PCB)从所在队列(或链表)中移出, 等待其他程序来搜集信息。
2.3.4 进程的阻塞与唤醒
1. 引起进程阻塞和唤醒的事件
- 向系统请求共享资源失败
- 等待某种操作的完成
- 新数据尚未到达
- 等待新任务的到达
2. 进程阻塞过程
正在执行的进程,当发现上述某事件时,由于无法继续执行,于是进程便通过调用阻塞原语block把自己阻塞。
进程的阻塞是进程自身的一种主动行为
。进入block过程后,由于此时该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由“执行”改为阻塞,并
将PCB插入阻塞队列
。如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将
本进程插入到具有相同事件的阻塞(等待)队列
。 最后,转调度程序进行
重新调度
,将处理机分配给另一就绪进程,并进行切换,亦即,
保留被阻塞进程的处理机状态(在PCB中),再按新进程的PCB中的处理机状态设置CPU的环境
。
3. 进程唤醒过程
当被阻塞进程所期待的事件出现时,如I/O完成或其所期待的数据已经到达,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup( ),将等待该事件的进程唤醒。唤醒原语执行的过程是:
首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中
。
block和wakeup原语必须成对使用。
2.3.5 进程的挂起与激活
1. 进程的挂起
当出现了引起进程挂起的事件时,比如,用户进程请求将自己挂起,或父进程请求将自己的某个子进程挂起, 系统将利用挂起原语suspend( )将指定进程或处于阻塞状态的进程挂起。挂起原语的执行过程是:首先
检查被挂起进程的状态
,若处于活动就绪状态,便将其改为静止就绪;对于活动阻塞状态的进程,则将之改为静止阻塞。 为了方便用户或父进程考查该进程的运行情况而
把该进程的PCB复制到某指定的内存区域
。最后,
若被挂起的进程正在执行,则转向调度程序重新调度
。
2. 进程的激活过程
当发生激活进程的事件时,例如,父进程或用户进程请求激活指定进程,若该进程驻留在外存而
内存中已有足够的空间
时,则可将在
外存上处于静止就绪状态的进程换入内存
。这时,系统将利用激活原语active( )将指定进程激活。
激活原语先将进程从外存调入内存
,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞便将之改为活动阻塞。假如采用的是抢占调度策略,则每当有新进程进入就绪队列时,应检查是否要进行重新调度,即由调度程序将被激活进程与当前进程进行优先级的比较,如果被激活进程的优先级更低,就不必重新调度;否则,立即剥夺当前进程的运行,把处理机分配给刚被激活的进程。
2.4 进程同步
2.4.1 进程同步的基本概念
1. 两种形式的制约关系
- 间接相互制约关系
- 直接相互制约关系
2. 临界资源(Critical Resouce)
临界资源或独占资源:把在一段时间内只允许一个进程访问的资源
生产者-消费者(producer-consumer)问题:所有的生产者进程和消费者进程都是以异步方式运行的,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品;也不允许生产者进程向一个已装满产品且尚未被取走的缓冲区中投放产品
3. 临界区(critical section)
把每个进程中访问临界资源的那段代码成为
临界区
。
4. 同步机制应遵循的规则
(1) 空闲让进。
(2) 忙则等待。
(3) 有限等待。
(4) 让权等待。
2.4.2 硬件同步机制
可将标志看成一个锁,锁开进入,锁关等待。
为防止多个进程同时测试到锁为打开的状态,测试和关锁操作必须是连续的,不能分开进行。
1. 关中断
在进入所测试之前关闭中断,直到完成锁测试并上锁之后才能打开中断。
2. 利用Test-and-Set指令实现互斥
“测试并建立”指令,是一条原语。
// lock=false资源空闲;lock=true资源被使用
Boolean TS(boolean *lock){
Boolean old;
Old = *lock;
*lock = true;
Return old;
}
Do{
…
while TS(&lock); //test until success
Critical section;
lock = false;
Remainder section;
}while(1);
3. 利用Swap指令实现互斥
交换两个字的内容
Void swap(boolean *a,boolean *b)
{
Boolean temp;
Temp=*a;
*a=*b;
*b=temp;
}
//为每个临界资源设置一个全局布尔变量lock,其初值为false;在每一个进程中再用一个局部布尔变量key。
Do{
Key=ture;
do {
swap(&lock,&key); //test until success
}while(key!=false);
Critical section;
lock=false;
…
}while(1);
利用硬件进行进程同步不符合“让权等待”原则,且难以解决复杂的进程同步问题
2.4.3 信号量机制
1. 整型信号
把整型信号量定义为用于
表示资源数目的整型量S
。除初始化外,仅能通过两个标准的
原子操作
(Atomic Operation) wait(S)和signal(S)来访问。这两个操作一直被分别称为P、V操作。
wait(S){
while(S<=0); /*do no-op*/
S--;
}
signal(S){
S++;
}
2. 记录型信号量
除了用于代表资源数目的整型变量value外,还增加一个进程链表指针list。
遵循“让权等待”准则
typedef struct{
int value; //资源信号量
struct process_control_block *list; //信号量链表
}semaphore;
wait(semaphore *S){
// 每次wait操作,意味着进程请求一个单位的该类资源,使系统中可供分配的该类资源少一个
S->value--;
// 该类资源已分配完毕,进程调用block原语自我阻塞,放弃处理机,并插入到信号量链表中
if(S->value<0) block(S->list);
}
//value的绝对值表示在该信号量链表中已阻塞进程的数目
signal(semaphore *S){
//每次signal操作不是进程释放一个单位资源,是系统中可分配的该类资源增加一个
S->value++;
//在该信号量链表中仍有等待该资源的进程被堵塞,应调用wakeup将list链表的第一个等待进程唤醒
if(S->value<=0) wakeup(S->list);
}
// 如果S.value的初值为1,表示只允许一个进程访问临界资源,此时的信号量转化为互斥信号量
3. AND型信号量
一个进程需要获得
两个或更多的共享资源
后才能执行任务
对若干个临界资源的分配采取原子操作方式,要把它所请求的资源
全部分配到进程,要么一个也不分配
。
Swait(S1,S2,...,S3){
while(TRUE){
if(Si>=1 && ... && Sn>=1){
for(i=1; i<=n; i++)Si--;
break;
}
else{
place the process in the waiting queue associated with the first Si found
with Si<1, and set the program count of this process to the beginning of
Swait operation
}
}
}
Ssignal(S1,S2,...,Sn){
while(TRUE){
for(i=1; i<=n; i++){
Si++;
Remove all the process waiting in the queue associated with Si into
the ready queue.
}
}
}
4. 信号量集
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xaFqjPgO-1622354196595)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a8124f93-dee6-43dd-bf58-2e0aee4810b2/Untitled.png)]
Swait(S1, t1, d1, …, Sn, tn, dn)
if Si≥t1 and … and Sn≥tn then
for i∶=1 to n do
Si∶=Si-di;
endfor
else
Place the executing process in the waiting queue of the first Si with Si<ti
and set its program counter to the beginning of the Swait Operation.
endif
signal(S1, d1, …, Sn, dn)
for i∶=1 to n do
Si ∶=Si+di;
Remove all the process waiting in the queue associated with Si into
the ready queue endfor;
一般“信号量集”的几种特殊情况:
(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后,将阻止任何进程进入特定区。换言之,它相当于一个可控开关。
2.4.4 信号量的应用
1. 利用信号量实现进程互斥
Var mutex:semaphore∶ =1;
begin
parbegin
process 1: begin
repeat
wait(mutex);
critical section
signal(mutex);
remainder seetion
until false;
end
process 2: begin
repeat
wait(mutex);
critical section
signal(mutex);
remainder section
until false;
end
parend
2. 利用信号量实现前趋关系
2.4.5 管程机制
1. 管程的定义
代表
共享资源的数据结构
以及由
对该共享数据结构实施操作的一组过程
所组成的资源管理程序共同构成了一个操作系统的资源管理模块,即管程。
管程由三部分组成:
- 管程的名字
- 局部于管程的共享变量说明;
- 对该数据结构进行操作的一组过程;
- 对局部于管程的数据设置初始值的语句。
2. 条件变量
若进程在管程中被阻塞或挂起,其他进程无法进入管程被迫长时间等待。为解决问题,引入条件变量condition。管程中对每个条件变量都给予说明,形式为condition x,y;
x.wait:正在调用管程的进程因x条件需要被阻塞或挂起,调用x.wait将自己插入到x条件的等待队列上并释放管程,知道x条件变化。此时其他进程可以用该管程
x.signal:正在调用管程的进程发现x条件发生变化,则调用x.signal,重新启动一个因x条件而阻塞或挂起的进程。
2.5 经典进程的同步问题
2.5.1 生产者—消费者问题
1. 利用记录型信号量解决生产者—消费者问题
假定在生产者和消费者之间的公用缓冲池中,具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。对生产者—消费者问题可描述如下:
2. 利用AND信号量解决生产者—消费者问题
3. 利用管程解决生产者-消费者问题
2.5.2 哲学家进餐问题
1. 利用记录型信号量解决哲学家进餐问题
为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组。其描述如下:Var chopstick: array[0, …, 4] of semaphore;
可采取以下几种解决方法:
(1) 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
(2) 仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐。
(3) 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。按此规定,将是1、 2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐
2. 利用AND信号量机制解决哲学家进餐问题
2.5.3 读者-写者问题
2. 利用信号量集机制解决读者-写者问题
2.6 进程通信
2.6.1 进程通信的类型
1. 共享存储器系统(Shared-Memory System)
(1)基于共享数据结构的通信方式。
(2) 基于共享存储区的通信方式。
2. 管道(Pipe)通信
3. 消息传递系统(Message passing system)
- 直接通信方式
- 间接通信方式
4. 客户机-服务器系统
-
套接字(Socket)
通信标识类型的数据结构,包含了通信目的地址、端口号、通信协议等等。可以用于计算机内部的进程通信,用可以用于网络中不同计算机间的进程通信。 -
远程过程调用RPC(Romote Procedure Call)和远程方法调用
用于通过网络连接的系统。允许本地进程调用远程主机上的进程。如果涉及面向对象编程,PRC也可称作为远程方法调用。引入了
存根
的概念。
2.6.2 消息传递通信的实现方式
1. 直接消息传递系统
发送进程利用OS所提供的发送命令,直接把消息发送给目标进程。
系统提供下述两条通信命令(原语):
Send(Receiver, message); 发送一个消息给接收进程;
Receive(Sender, message); 接收Sender发来的消息;
在接收进程接收消息的原语中的源进程参数,是完成通信后的返回值,接收原语可表示为:
Receive (id, message);
2. 信箱通信
Send(mailbox, message); 将一个消息发送到指定信箱;
Receive(mailbox, message); 从指定信箱中接收一个消息;
类型
- 私用信箱
- 公用信箱
2.6.3 直接消息传递系统实例
1. 消息缓冲队列通信机制中的数据结构
- 消息缓冲区
- PCB中有关通信的数据项(在利用消息缓冲队列通信机制时,在设置消息缓冲队列的同时,还应增加用于对消息队列进行操作和实现同步的信号量,并将它们置入进程的PCB中)
2. 发送原语
2.7 线程的基本概念
2.7.1 线程的引入
为了使多个程序能够更好地并发执行,又尽量减少系统的开销,由此引入线程的概念:将进程的
资源属性和调度属性
分开,
对拥有资源的基本单位不做频繁的切换,而只对调度和分派
的单位进程(即线程)进行调度。
线程—作为调度和分派的基本单位
。
2.7.2 线程与进程的比较
(1)调度的基本单位(线程切换时仅需保存和设置少量寄存器内存,切换代价远低于进程)
(2) 并发性(不同线程之间也可以并发执行)
(3) 拥有资源(线程本身无系统资源,仅有一点必不可少的能确保独立运行的资源;线程允许多个线程共享该进程所拥有的资源)
(4) 独立性(同一进程的不同线程之间的独立性要比不同进程之间的独立性低得多)
(5)系统开销(线程更低)
(6)支持多处理机系统
2.7.3 线程的状态和线程控制块
1. 线程运行的三个状态
- 执行状态
- 就绪状态
- 阻塞状态
同进程的三个状态
2. 线程控制块(TCB)
同进程控制块。系统为每个线程配置了一个线程控制块TCB,将所有用于控制和管理线程的信息记录在TCB中。
3. 多线程OS中的进程有以下属性
(1) 进程是一个可拥有资源的基本单位,作为系统资源分配的单位。
(2) 可包括多个线程,多个线程可以并发执行。
(3)
进程不是一个可执行的实体
。在多线程OS中,把线程作为独立运行的基本单位。
2.8 线程的实现
2.8.1 线程的实现方式
1. 内核支持线程KST
但一个线程切换到另一个线程时,需要从用户态转到核心态进行。因为用户进程的线程是指用户态运行,而线程调度和管理是在内核实现的。
调度以线程为单位进行
2. 用户级线程ULT
在用户空间实现,与内核无关。
调度以进程为单位进行
。
3. 组合方式
多对一模型
一对一模型
多对多模型
2.8.2 线程的实现
1. 内核支持线程的实现
类似进程
2. 用户级线程的实现
在用户空间实现,所有的用户级线程都具有相同的结构,他们都允许在一个中间系统上。
1)运行时系统
所谓“运行时系统”是用于
管理和控制线程的函数(过程)的集合
。用户级线程在切换时不需要转入核心态,而是由运行时系统中的线程切换函数来执行切换任务。运行时系统中的所有函数都驻留用户空间,并作为用户级线程与内核之间的接口。
2)内核控制线程
又称为轻型进程LWP,LWP通过系统调用访问内核。用户线程需要与内核通信时才借助LWP访问内核。将内核与用户级线程隔离。当一个系统用户级线程数量很大时,为了节省系统开销,把这些LWP做成一个缓冲池,即“线程池”。任一用户线程都可连接到线程池的任何一个LWP上。
2.8.3 线程的创建和终止
1. 创建
2. 终止