操作系统是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源的分配,以提供给用户和其他软件方便的接口和环境的程序集合。
两个最基本的特征:
其他特征:
用户态和核心态的切换,需要用到中断或异常实现,包括两种类型:
系统调用命令按照功能分为:设备管理、文件管理、进程控制、进程通信、内存管理
总结: 系统运行环境可以理解为,用户通过操作系统运行上层程序,而上层程序依赖于操作系统底层管理和程序提供服务支持,当需要管理程序服务时,系统则通过硬件中断机制或异常处理进入核心态。当管理程序结束时,通过相应的保存程序现场退出中断处理程序或异常处理程序,返回中断点,继续执行上层程序。
进程通常有以下五种状态:
进程控制包括进程创建、进程终止、进程阻塞和唤醒、进程切换
进程创建(创建原语): 进程的创建如下:
进程终止(撤销原语): 引起进程终止的情况有正常结束和异常结束两种。进程终止的过程为:
进程的阻塞和唤醒
阻塞的过程为:
唤醒的过程:
进程切换: 指处理机从一个进程的运行状态转到另一个进程上运行,过程如下:
进程一般由三个部分组成:
进程通信指进程间的信息交换,高级通信方法分为三类:
调度: 从就绪队列中,按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程并发执行。
三级调度:
可以调度的时机:
不可调度的情况:
选择调度算法时的评价准则有以下几种:
CPU利用率: 尽可能不让CPU空闲
系统吞吐量: 表示单位时间内CPU完成作业的数量。长作业会导致吞吐量降低。
周转时间: 指从作业提交到作业完成所经历的是时间,包括作业等待、在就绪队列中排队,在处理机上运行,以及输入、输出操作所花费的时间总和。
等待时间: 作业在就绪队列中等待的时间。处理机调度算法并不影响作业执行输入、输出的时间,只影响等待时间,故衡量调度算法通常仅需要考虑等待时间。
响应时间: 指从用户提交请求到系统首次产生响应所用的时间。
①先来先服务(FCFS)调度算法: 同时适用于作业调度和进程调度,其调度原则都是选择最先进入队列的作业或进程。属于不可剥夺算法。
②短作业优先(SJF)调度算法: 适用于作业调度和进程调度。基本原则是,从后备队列中选择一个或多个估计运行时间最短的作业(进程)调度使用。
③优先级调度算法: 适用于作业调度和进程调度。基本原则是每次从后备作业中,选择优先级最高的作业进行调度。
按照更高优先级能否抢占正在执行的进程,可将该算法分为:
按照进程创建后优先级是否可以改变,可将该算法分为:
④高响应比优先调度算法: 主要用于作业调度。是对FCFS和SJF调度算法的一种综合平衡,同时考虑每个作业等待时间和估计运行时间,每次作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。响应比计算公式:
特点:
⑤时间片轮转调度算法: 主要适用于分时系统,系统将所有就绪进程按到达时间的先后次序排成一个队列,进程调度程度总是选择就绪队列中的第一个进程执行,即先来先服务的原则,但仅能运行一个时间片。使用完一个时间片后,即使进程未完成运行,也必须释放出处理机给下一个就绪的进程,而自己则返回到就绪队列的队尾重新排队等候再次运行。
该算法性能主要影响因素为时间片大小,时间片大小的决定因素通常有:系统响应时间、就绪队列中的进程数目和系统的处理能力。
⑥多级反馈队列调节算法: 是时间片轮转调度算法和优先级调度算法的综合和发展。特点如下:
优势为:
软件实现方式:
①单标志法: 设置一个变量,用于指示被允许进入临界区的进程编号。缺点是两个进程必须交替进入,如果某个进程不再进入临界区了,那另一个也将无法进入。违背“空闲让进”原则。
②双标志法先检查: 设置一个数组flag
,第i个进程,如flag[i]
为false,则表示未进入临界区。缺点是可能会导致多个进程同时进入临界区,违背”忙则等待“原则。
③双标志法后检查: 先设置自己标志为True后,再检测对方状态,如果对方状态为True,则等待,否则进入临界区。缺点是,两个进程几乎同时想进入临界区时,很容易相互谦让,造成饥饿。
④Peterson’s 算法: 为防止两个进程为进入临界区无限期等待的状况发生,又设置变量turn,每个进程在先设置自己标志后再设置turn标志,这时再同时检测另一个进程状态标志和不允许进入标志。这样可以保证当两个进程同时要求进入临界区,只允许一个进入。
理解: pi进程,一旦设置flag[i]=true
,则pj不能进入。如果pj已经进入临界区,则flag[j]=true
,pi就不能进入。同时,饥饿现象也被避免了,因为如果pi被阻塞,表示flag[i]=true&&turn=j
,这样pj不会被阻塞。
硬件实现方式:
①中断屏蔽法: 因为CPU只在中断发生时引起进程切换,屏蔽一切中断的发生,就能保证当前运行进程将临界区代码顺利执行完,从而保证了互斥的正确实现。
②硬件指令方法:
信号量可用来解决互斥与同步的问题,只能被两个标准的原语wait(P操作)和signal(V操作)来访问。有以下几种类型:
①整型信号量: 定义为一个用于表示资源数目的整数S,wait和signal操作可以表示为:
整型信号量知道S<=0
,就会一直测试,让进城处于”忙等“的状态。
②记录型信号量: 除了需要一个用于代表资源数目的整数value外,在增加一个进程链表L,用于链接所有等待该资源的进程。wait操作可表示为:
上述代码中,value表示资源数量。当value<0
时,表示资源已经分配完了,没可用资源,因此进程调用block原语,进行自我阻塞,放弃处理机,并插入到资源等待队列L中。
signal操作表示为:
当value<0
时,表示归还资源后,等待队列中还有阻塞的进程,故调用weakup原语唤醒L中第一个等待唤醒的进程。
利用信号量,可以实现互斥和同步以及前驱关系:
①生产者-消费者问题: 需要设置三个信号量:互斥信号量mutex
,初始值为1;满信号量full
,初始值为0;空信号量empty
,初始值为n。具体操作如下:
②读者-写者问题: 有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生问题,但如果某个写进程和其他进程(读进程和写进程)同时访问共享数据时则可能导致数据不一致。要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前,不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出
第一种写法:
上面的写法是读优先的,容易导致写进程饿死,因此有了下一种写法:
③哲学家进餐问题: 如下图,一张桌子上坐着5个哲学家,每两个哲学家之间摆一根筷子,每个哲学家面前有一碗米饭。哲学家饿了时,试图拿筷子,只有拿到两根筷子,才能进餐。为了防止死锁或饥饿现象,有两种解决方案:①让他们同时拿两个筷子;②对每个哲学家的工作制定规则,避免饥饿或死锁发生。
解决方法: 定义一个互斥信号量数组chopstick[5]={1,1,1,1,1}
,用于5个筷子的互斥访问。对哲学家按照0~4编号,哲学家i左边的筷子为i,右边的筷子为(i+1)%5
。
当五个哲学家都要进餐,分别拿了左边的筷子时(其实不需要5个,只要相邻的两个哲学家,同时拿了左边的筷子),就拿不到右边的筷子了,这样就出现了死锁。
④吸烟者问题: 有三个抽烟者,一个供应者。每个抽烟者不停卷烟并抽烟,抽烟的原材料有:烟草、纸、胶水。三个抽烟者分别拥有三种材料中的一种。供应者每次随机地将两种材料放到桌上,这时拥有剩余材料的抽烟者就卷烟并抽烟。
解决方法: 设置offer1
、offer2
、offer3
三个信号量分别表示烟草和纸、烟草和胶水、胶水和纸组合,信号量finish用于互斥地进行抽烟动作。
①预防死锁:资源分配前,设置某些限制条件,破坏产生死锁的四个必要条件中的一个或几个
②避免死锁: 在资源分配过程中,用某种方法防止系统进入不安全状态,从而避免死锁
③检测死锁并解除: 通过系统的检测及时检测出死锁的发生,然后采取某种措施解除死锁(通常需要剥夺资源)。
资源分配图: 用资源分配图来描述资源分配过程,图中用圆圈代表进程,框代表一类资源,从进程到资源的有向边叫请求边,表示进程申请一个单位的该类资源;从资源到进程的边叫分配边,表示该类资源已经有一个资源被分配给了该进程。
死锁定理: 通过资源分配图来检测是否存在死锁,过程为:
①在资源分配图中,找出既不阻塞又不是孤立点的进程Pi(==即找到有一条有向边与进程结点相连,且该有向边对应资源的申请数量小于等于系统中已有空闲资源数量),消去它所要的请求边和分配边,使之成为孤立节点。
②进程Pi所释放的资源,可以唤醒某些因为等待这些资源而阻塞的进程,原来阻塞的景进程可以变成非阻塞状态。如下图,P2就可以变成非阻塞。
③不断执行上述两步,若能消去所有边,则该资源分配图就是可简化的。出现死锁的添加是资源分配图不可简化,该条件称为死锁定理。
发现死锁后,可通过采取措施解除死锁:
①涉及的数据结构:
1)可利用资源向量Avaliable: 这是一个含有 m 个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。如果 Available[j] = K,则表示系统中现Rj类资源K个。
2)最大需求矩阵Max: 这是一个n * m
的矩阵,它定义了系统中n个进程中的每个进程对m类资源的最大需求。如果Max[i,j] = K,则表示进程i需要Rj 类资源的最大数目为K。
3)分配矩阵 Allocation: 这也是一个n * m
的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果 Allocation[i,jl = K,则表示进程i当前己分得Rj类资源的数目为K。
4)需求矩阵Need: 这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j] = K,则表示进程i还需要Rj类资源K个方能完成其任务。
三个矩阵的关系为:
Need[i,j]=Max[i,j]-Allocation[i,j]
②算法描述
设Requesti为进程Pi的请求矢量,如果Requestii=K,表示进程Pi需要j类资源K个。发出资源请求后,系统按照如下步骤检查:
1)如果 Requesti[j] ≤ Need[i,j]便转向步骤2);否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
2)如果 Requesti[j] ≤ Available[j],便转向步骤3);否则,表示尚无足够资源,Pi须等待。
3)系统试探着把资源分配给进程Pi,并修改下面数据结构中的数值
Available[j] = Available[j] - Requesti[j];
Allocation[i,j] = Allocation[i,j] + Requesti[j];
Need[i,j] = Need[i,j] - Requesti[j]
4)系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。
③安全算法:
(1) 设置两个向量:①工作向量Work,它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素,在执行安全算法开始时,Work = Available
;② Finish,它表示系统是否有足够的资源分配给进程,使之运行完成。开始时先做 Finish[i] = false;当有足够资源分配给进程时,再令Finish[i] = true。
(2) 从进程集合中找到一个能满足下述条件的进程
若找到,执行步骤(3),否则,执行步骤(4)。
(3)当进程Pi获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
Work[j] = Work[j] + Allocation[i,j];
Finish[i] = true;
go to step 2;
(4)如果所有进程的 Finish[i] =true都满足,则表示系统处于安全状态;否则,系统处于不安全状态。
进程运行的一些基础知识:
①程序装入和连接: 将程序和数据装入内存,将用户源程序变成可在内存中执行的程序,需要以下步骤:
1)编译
2)链接: 将编译后的模块以及所需要的库函数链接在一起,形成一个完成的装入模块。链接分为静态链接和动态链接:
3)装入: 由装入程序装入模块装入内存运行。分为绝对装入和可重定位装入:
②逻辑地址空间与物理地址空间:编译后,每个目标模块都是从0号单元开始编址,称为该目标模块的相对地址。系统会进行相对地址到绝对地址的映射和转换。
③内存保护: 内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。可采用两种方法:
覆盖和交换是在多道程序环境下用来扩充内存的两种方法
指给用户分配一个连续的内存空间,包括单一连续分配、固定分区分配和动态分区分配
单一连续分配: 内存在此方式下分为系统区和用户区,系统去仅仅给操作系统使用。这种方式无需内存保护,因为内存中永远只有一道程序,不会发生越界。
固定分区分配: 将用户内存空间划分为若干个固定大小的区域,每个分区只能装入一道作业。当有分区空闲时,便可以再从外存的后备作业队列中,选择适当大小的作业装入该分区。该方式在划分分区时,有分区大小相等和大小不等两种情况。
存在的问题:①可能程序太大不能放入任何分区,需要使用覆盖技术来使用内存空间;②主存利用率小,当程序小于分区大小时,也占了一个完整的分区空间,形成内部碎片,造成空间浪费。
动态分区分配: 这种方法不预先划分内存,而是在进程装入内存时,根据进程的大小动态地创建分区,并使分区的大小正好适合进程的需要。动态内存分配会导致内存中出现外部碎片,这种问题可以通过紧凑技术来解决
该方式允许将一个程序分散地装入到不相邻的内存分区中。根据分区的大小是否固定,分为分页存储管理方式和分段存储管理方式。
(1)基本分页存储管理方式——有利于提高内存利用率
①分页的基本思想:将内存划分为大小相等且固定的块,块相对较小,作为主存的基本单位。每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。
②分页存储的基本概念:
1)页面和页面大小:进程中的块称为页,内存中的块称为页框,外存中也以同样方法划分,称为块。进程在执行时,需要申请主存空间,就是要为每个页分配页框。为方便转换,页面大小应是2的整数幂。同时页面大小应该适中。
2)地址结构:分页存储管理的逻辑地址结构如下所示:
逻辑地址包含两部分第一个是页号,第二个是页内偏移量,表示相对P页开始的位置。逻辑地址长度为32位,0-11位为页内地址,即每页大小为4KB;12-31位为页号,地址空间最多允许有220页。
3)页表:为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立了一张页表,记录页面在内存中对应的物理块号。页表一般放在内存中,作用是实现从页号到物理块号间的地址映射。
③基本地址变换机构
地址变换结构的任务是将逻辑地址转换为内存中的物理地址,变换借助页表实现。
设页面大小为L,逻辑地址A到物理地址E的变换过程如下,
④具有块表的地址变换机构
若页表全部放在内存中,则存取一个数据或一条指令至少要访问内存两次(一次度页表数据,另一次根据地址读内存),速度较慢。故在地址变换机构中,增设一个具有并行查找能力的高速缓冲器——快表,又称联想寄存器,以加速查找过程。
在有快表的地址变换结构中,地址变换过程为:
⑤两级页表
如果使用一级页表,页表占用的空间会非常大,故采用页表映射的思想,使用层次结构的页表,建立上一级页表,用于存储页表的映射关系。进程执行时,只需要将第一级页表调入内存,根据第一级页表找到找到第二级页表号,再根据第二级页表号去映射物理地址。
(2)基本分段存储管理方式——有利于反映程序的逻辑结构并有利于段的共享
(3)段页式管理方式
将页式管理方式和段式管理方式结合起来,形成段页式存储管理方式。在该系统中,作业的地址空间首先被分为若干个逻辑段,然后再将每一段分为若干个大小固定的页。而对于内存的管理,仍使用页式管理。
此时,作业的逻辑地址就分为三个部分:
地址变换过程如下:
(1)传统内存管理方式的不足:
(2)局部性原理
(3)虚拟存储器的定义和特征
(4)虚拟内存技术的实现
虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。有三种实现方式:
请求分页系统,在基础分页系统的基础上,增加了请求调页功能也页面置换功能。在该系统中,只要将当前需要的一部分页面装入内存,便可启动作业运行。在作业执行过程中,当所要访问的页面不在内存时,再通过调页功能将其调入,同时还可以利用置换功能将暂时不同的页面换出到外存上,以腾出内存空间。需要以下机制的支持:
①页表机制: 不同于基础分页管理系统,在请求页表项中新加了以下字段
②断页中断机制: 在请求分页系统中,每当所要访问的页面不在内存时,便产生一个断页中断,请求操作系统将所需的页调入内存。此时应将缺页的进程堵塞(调页完成唤醒)。
好的页面置换算法要有较低的页面更换频率。常见的算法有:
①最佳置换算法: 选择被淘汰的页面将是以后永远不使用的,或是最长时间内不再被访问的页面,这样可以保证最低的缺页率。但是由于无法知道哪些页面最长时间不再访问,故该算法无法实现。但该算法经常用来评价其他算法。
②先进先出页面置换算法: 优先淘汰最早进入内存的页面,亦即在内存中驻留时间最久的页面。该算法虽然实现简单,但有以下缺点:
③最近最久未使用算法: 选择最近最长时间未访问过的页面予以淘汰。该算法性能较好。但是需要栈和寄存器的硬件支持,实现困难且开销大。
④时钟置换算法: 时钟替换算法的具体规则如下(参考博客):
可以在使用位的基础上,再增加一个修改位,得到改进型的CLOCK置换算法。此时,每一帧都处于下下面四种情况之一:
算法的操作步骤如下(参考博客):
页面分配需要考虑的问题:
基于上面的因素,通常采用以下三种页面分配策略:
调入页面的时机
一般情况下,两种策略都会使用。
指的是在某段时间间隔内,进程要访问的页面集合。经常被使用的页面需要再工作集中,而长期不被使用的页面要从工作集中丢弃。为防止抖动的出现,要选择合适的工作集大小。
文件: 由创建者定义的一组相关信息的集合。
文件的结构:
无结构文件: 将数据按顺序组织成记录并积累保存,以字节为单位,常用于对基本信息单位操作不多的文件,如程序代码等。
有结构文件: 按照记录的组织方式可以分为:
1)顺序文件: 文件的记录一个一个地顺序排列
2)索引文件: 利用索引表保存记录位置,查找时根据索引表查找以提高检索速度。索引表本身是定长记录的顺序文件。
3)索引顺序文件: 顺序和索引文件两种组合形成的。
4)直接文件或散列文件: 通过散列值来定位物理地址的文件
文件分配方式:
连续分配:每个文件在磁盘上占用一组连续的块,磁盘地址定义了磁盘上的一个线性排列。优点是实现简单,存取速度快。缺点是文件长度不宜动态增加,一旦需要增加就要移动大量的盘块。
链接分配: 链式分配,有隐式和显式两种方式。隐式方式类似于链表,优点是不会产生碎片,文件动态增长方便。缺点是,无法直接访问盘块,只能从头指针顺序访问文件。显式方式,在内存中有一个文件分配表,显式地存放对应块的下一块链接指针,即下一个块号。可以显著地提高检索速度,大大减少访问磁盘的次数。
索引分配: 在链接分配的基础上,把每个文件所有的盘块号集中放在一起构成索引块(表)。为了解决索引块过大的问题,可以使用链接方案(多个索引块以链表的方式链接起来)、多层索引方案、混合索引方案(多种索引分配方式相结合)。
文件存储空间管理: 文件存储设备分成许多大小相同的物理块,并以块交换信息,故文件存储空间管理,其实是对空闲块的组织和管理。有以下方法:
②空闲链表法: 属于链接分配。有以下两种链表方式
③位示图法: 利用二进制的一位来表示磁盘中盘块的使用情况,每个盘块都有一个二进制位与之对应。0表示空闲,1表示占用。分配时,根据表中的信息来分配。
④成组链接法(UNIX中使用): 上述方法不适用于文件太大的情况,成组链接法可以解决。这种方法结合了空闲表和空闲链表两种方法,大致思想是:把顺序的n个空闲扇区地址保 存在第一个空闲扇区内,其后一个空闲扇区内保存另一个顺序空闲扇区的地址,如此继续,直到所有的空闲扇区均予以链接。
磁盘盘面
磁盘结构
磁盘由磁头臂、用于旋转的主轴和用于数据输入输出的电子设备组成。所有盘面上相对位置相同的磁道组成柱面。磁盘地址用 “柱面号+盘面号+扇区号” 表示
磁盘读写操作的时间组成
磁盘调度算法: