注意:
这篇总结文档参考的配套书籍为《计算机操作系统》(第四版) 相关知识点关联的页码可能只与本书配套。
说明:
由于时间关系,该总结的部分知识点可能有所疏落或存在错误,请认真研读不要盲目学习,读者如有补充或问题更正请联系作者[[email protected]],作者将会表示感谢!
最后,希望尊重作者劳动成果,该文档仅供学习交流使用,请大家转载时注明出处,Thanks!
操作系统是一组能有效的组织和管理计算机硬件和软件资源,合理的对各类作业进行调度,以及方便用户使用的程序的集合。
并发
、共享
、虚拟、异步
并发:
两个或多个事件在同一时间间隔内发生。
并行:
两个或多个事件在同一时刻发生。
(1)处理机管理功能
(2)存储器管理功能
(3)设备管理功能
(4)文件管理功能
(5)提供与用户之间的接口
(1)间断性
(2)失去封闭性
(3)不可再现性
扩展:
程序顺序执行时的特性:①顺序性 ②封闭性 ③可再现性
进程实体 = 程序段 + 相关数据段 + 进程控制块(PCB)
(1)进程是程序的一次执行
(2)进程是一个程序及其数据在处理机上顺序执行时所发生的活动
(3)进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
总结:
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
扩展:
进程的特性:①动态性 ②并发性 ③独立性 ④异步性 ⑤结构性 (可不写)
进程的三种基本状态:
就绪(Ready)状态、执行(Running)状态、阻塞(Block)状态
常见问题:
当n个进程并发执行时,在单处理机中:
处于就绪状态的最多n-1
个,最少0
个
处于阻塞状态的最多n
个,最少0
个
处于执行状态的最多1
个,最少0
个
(1)直接制约(同步关系):
某些应用程序,为了完成某个任务而建立了两个或多个进程(源于进程间的合作)。
关于直接制约关系的举例:
(2)间接制约(互斥关系):
多个程序并发执行时,由于共享系统资源(如CUP、I/O设备等)而导致这些并发执行的程序之间形成相互的制约的关系。
(1)空闲让进
(2)忙则等待
(3)有限等待
(4)让权等待
记录型信号量是一种不存在“忙等”现象的进程同步机制。
typedef struct{
int value; //资源个数
struct process_control_block *list; //阻塞队列
}semaphore;
wait(semaphore *S){
S->value--; //S->value初值表示系统中某类资源的数目,称为资源信号量
if(S->value<0){
//自我阻塞
block(S->list);
}
}
signal(semaphore *S){
S->value++;
if (S->value <= 0){
//唤醒,将S->list链表的第一个等待线程唤醒
wakeup(S->list);
}
}
有兴趣看代码实现的同学可以读下这篇文章:https://blog.csdn.net/Mr_YanMingXin/article/details/118104845
A用完B用,A和B就是互斥
semaphore mutex = 1;
Pa(){
while(1){
wait(mutex);
临界区;
signal(mutex);
剩余区;
}
}
Pb(){
while(1){
wait(mutex);
临界区;
signal(mutex);
剩余区;
}
}
设有两个并发执行的进程P1和P2。P1中有语句S1;P2中有语句S2,我们希望在S1执行之后再执行S2
,为实现这种前驱关系,只需进程P1和P2共享一个公用信号量S,并赋予其初值为0,
将signal(S)操作放在语句S1的后面,而在S2语句的前面插入wait(S)操作,即
在进程P1中,用S1;signal(S)
在进程P2中,用wait(S);S2
由于S被 初始化为0,这样若先执行S2必为阻塞
,只有在进程P1执行完S1;signal(S)操作后使S变为1是,P2进程才能成功执行语句S2。
引入线程后:资源分配还是进程,但是资源调度变为了线程
前言:
引入进程–>为了多个程序并发执行,提高资源利用率和吞吐量。
引入线程–>为了减少程序在并发执行时所付出的时空开销,使系统具有更好的并发性。
定义:
线程是进程的一个实体,是独立调度的一个基本单位。
(1)低级调度:
[最基本的调度,在多道批处理、分时和实时的三种类型的OS中必须配置] 又称为进程调度或短程调度,调度对象为进程
,主要功能是根据某种算法,决定就绪队列中的哪个进程应获得处理机,并由分派程序将处理机分配给被选中的进程。
(2)中级调度:
又称为内存
调度,主要目的是提高系统内存的利用率和系统的吞吐量,实际上就是存储管理器中的对换功能。
(3)高级调度:
[主要用于多道批处理系统] 又称为长程调度或作业调度,调度对象为作业,主要功能是根据某种算法,决定将外存中处于后备队列中的哪几个作业调入内容,为他们创建进程、分配必要的资源,并将其放入队列。
小扩展:
运行频率 : 低级调度 > 中级调度 > 高级调度
(1)先来先服务(FCFS):
最简单的调度算法,可用于作业调度和进程调度,主要思想就是按照作业到达的先后顺序来进行调度。
(2)短作业优先(SJF):
根据作业的时间长短来决定作业的优先级,时间越短优先级越高,作业的长短是指作业要求的运行时间决定,从后背队列中选择时间短的优先执行。
(3)优先级调度算法(PSA):
核心在于确定作业的优先级,可用于进程调度和作业调度,使用该算法进行作业调度时需要事先在外部定义好该作业的优先级。
(4)高响应比调度算法(HRRN):
既考虑作业的运行时间,又考虑作业的等待时间,设置优先级为动态,规律为:
产生死锁的必要条件:
(1)互斥条件
(2)请求和保持条件
(3)不可抢占条件
(4)循环等待条件
预防死锁:
(1)破坏“请求和保持条件”
(2)破坏“不可抢占”条件
(3)破坏“循环等待”条件
银行家算法—避免死锁(P122):
什么是银行家算法?
[百度百科]:在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行.
银行家算法的数据结构:
(1)可利用资源向量Available
是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有R类资源K个。
(2)最大需求矩阵Max
这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要R类资源的最大数目为K。
(3)分配矩阵Allocation
这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得R类资源的 数目为K。
(4)需求矩阵Need
这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要R类资源K个,方能完成其任务。
Need [ i, j ] = Max [ i , j ] - Allocation [ i , j ]
解释一下:就是让需求等于已经分配的加上再向操作系统请求的,比如对于P0进程,该公式换算后的结果就是
0 0 1 2 = 0 0 4 4 - 0 0 3 2 就可以根据任意两个变量计算出第三个变量
算法原理:
[百度百科]:我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.
操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。
例题:
在银行家算法中,若出现下述资源分配情况:
(1)当前系统状态是否安全?
(2)如果进程P2提出请求Request2(1,1,2,2)后,系统能否将资源分配给它?
解答:
(1)安全,安全序列为[P0,P3,P1,P2,P4]
(2)不能,理由如下:
假设将(1,1,2,2)分配给Request2,则P2进程仍然需要Need(1,2,3,4),此时系统剩余可用Available(0,5,0,0),不能满足任何进程的需要,所以分配给Request2为不安全行为。
PS Java实现银行家算法:https://blog.csdn.net/Mr_YanMingXin/article/details/117996596
(1)绝对装入方式
[只适用于单道程序环境] 用户程序经过编译之后,会产生一个绝对的地址(物理地址)的目标代码(模块/装入模快),绝对装入程序就可以按照装入模快的地址将程序和数据装入内存,装入内存之后,程序的相对地址(逻辑地址)和实际内存地址(物理地址)完全相同,所以不需要地址转换。
(2)可重定位装入方式(静态重定位)
[主要适用于多道程序环境,不需要硬件支持] 根据内存的具体情况将装入模快装入到内存适当的位置,而且会使装入模块的内存的地址(逻辑地址)和实际装入内存后的物理地址不同。地址变换在进程装入时一次性完成,以后不再改变,所以叫做静态重定位。
(3)动态运行时的装入方式(动态重定位)
[目前主流,主要用于多道程序环境,需要硬件支持] 把装入模块装入内存后,并不立即把装入模块中的逻辑地址转换为物理地址,而是等到该程序真正的执行的时候再进行地址的转换。因此装入内存后的地址仍然都是逻辑地址。
(1)单一连续分配
[单道程序环境下适用,最简单的分配方式] 把内存分为系统区和用户区两个部分,系统区只给OS(系统)适用,通常放在内容的低址部分。在用户区部分,仅装有一道用户程序(独占)。这样的方式成为单一连续存储方式。
(2)固定分区分配
[分区个数固定,可运行多道程序] 将这个用户空间化成若干个固定大小的区域,每个分区只装入一道作业,于是就形成了多道程序的分区存储管理方式。
(3) 动态分区分配
**[分区个数、大小都可变]**又称为可变分区分配,就是根据进程的实际需要,动态的为之分配内存。
(4)*基于顺序搜索的动态分区分配
核心思想:将空闲分区链以地址递增的次序进行链接,分配内存时从头部开始查找,直到找到一个大小能满足要求的空闲分区为止。
核心思想:将空闲分区链以地址递增的次序进行链接,分配内存时从上次找到空闲分区的下一个分区开始查找,直到找到一个大小能满足要求的空闲分区为止。
核心思想:将空闲分区按空间从小到大进行排序,依此进行查找(避免大材小用),知道找到满足要求的空闲分区。
核心思想:将空闲分区按空间从大到小进行排序,总是挑选一个最大的空闲分区,从中分配一部分空间给作业使用。
分页存储管理的基本方法
1.页面和物理块:
(1)页面:
分页存储管理将进程的逻辑地址空间分成若干个页,并为各页加以编号,从0开始。把内存的物理空间分成若干个块,同样加以编号从0开始。为进程分配内存时,以块为单位,将进程的若干个页分别装入到多个可以不相邻接的物理块中。由于进程最后一页通常装不满一块,则剩余页面叫做“页内碎片”。
(2)页面大小:
页面大小应选择适中,并且应该是2的N次幂,通常为1KB~8KB
2.地址结构:
说明:如上图可知,地址长度为32位,其中011为页内地址,即每页大小为4KB(2的12次方),1231位为页号,即地址空间最多有1M页(2的20次方)
计算:对于某种特定的机器,其地址结构是一定的,若给定一个逻辑空间中的地址为A,页面大小为L,则页号P和页内地址d可由公式计算:
例如页面大小L为1KB,逻辑空间A为2170B,由上式可求得页号P=2170/1024取整为2,页内地址d=2170对1024取余结果为122.
3.页表和地址映射:
目的:
为了满足用户在编程和使用上的多方面要求。
地址结构:
在分段存储管理中,作业的地址空间被划分成若干个段,每个段定义了一组逻辑信息。
在该地址结构中,允许一个作业最长有64K个段,每个段的最大长度为64KB。
段表:
在分段管理中,系统为每个进程分段分配一个连续的分区,就需要为每个进程建立一张映射表,称为“段表”。
该表记录了该段在内存中的起始地址(“基址”)和段的长度,作用是用于实现逻辑段到物理内存区的映射。
基本原理:
先将用户的程序分成若干个段,再把每个段分成若干个页,并为每个段赋予一个段名。
一条指令的执行需要三次访问内存。
下一篇:https://blog.csdn.net/Mr_YanMingXin/article/details/117990261