【操作系统】

面试题目收集

  1. https://blog.csdn.net/crazymakercircle/article/details/128708648
  2. https://blog.csdn.net/m0_54355125/article/details/124091010
  3. https://www.nowcoder.com/discuss/353159072050520064
  4. https://www.cnblogs.com/javaguide/p/17312118.html

第一章

一、操作系统的定义

操作系统是一组计算机程序的集合,用于控制和管理硬件资源和软件资源,合理地组织计算机的工作流程,为用户提供方便、快捷、友好的应用程序使用接口。

  • 是系统最基本最核心的软件,属于系统软件
  • 控制和管理整个计算机的硬件和软件资源
  • 合理的组织、调度计算机的工作与资源的分配
  • 为用户和其它软件提供方便的接口和环境

二、操作系统的特征

  1. 并发性
    两个及以上的进程在同一个时间间隔内同时运行。

注:并行是同一个时间点,并发是同一个时间段。

一个单核(CPU)同一时刻只能执行一个程序,因此操作系统会协调多个程序使他们交替进行(这些程序在宏观上是同时发生的,在微观上是交替进行的)。操作系统是伴随着“多道程序技术出现的”,因此操作系统和并发是一同诞生的。在如今的计算机中,一般都是多核cpu的,即在同一时刻可以并行执行多个程序,比如我的计算机是8核的,我的计算机可以在同一时刻并行执行8个程序,但是事实上我们计算机执行的程序并不止8个,因此并发技术是必须存在的,并发性必不可少。

  1. 共享性
    内存中并发执行的多个程序可以共享计算机的硬件资源和软件资源。
    分为互斥共享和交替共享,
  • 互斥共享:利用信号量或其他手段;
  • 交替共享:所谓的“同时”往往是宏观上的,而在微观上,这些用户或程序可能是交替地对该资源进行访问,例如对磁盘设备的访问
  1. 随机性
    也叫异步性。每道程序在何时执行、各个程序执行的顺序以及每道程序所需要的时间都是不确定的,也是不可预知的。

中断的存在导致一个程序很可能不是一次性运行完,而是运行与等待交替进行

  1. 虚拟性
    将一个物理实体映射为一个或多个逻辑对象。

三、操作系统的功能与分类

操作系统的功能

从资源管理角度来讲,操作系统具有以下五大基本功能:

  1. 进程和线程的管理
    在多道程序环境下,cpu的分配和运行都以进程(或线程)为基本单位,因此对cpu的管理可理解为对进程的管理。进程管理的主要功能包括:进程控制、进程同步、进程通信、死锁处理、处理机调度
  2. 存储管理
    为多道程序的运行提供良好的环境,方便用户使用及提高内存的利用率,主要包括:内存分配与回收、地址映射、内存保护与共享和内存扩充等功能。
  3. 文件管理
    计算机中所有的信息都是以文件的形式存在的,操作系统中负责文件的管理的部分称为文件系统,文件管理包括:文件存储空间的管理、目录管理及文件读写管理和保护
  4. 设备管理
    设备管理的主要任务是完成用户的I/O请求,方便用户使用各种设备,并提高设备的利用率,主要包括:缓存管理、设备分配、设备处理和虚拟设备等功能。
  5. 用户接口
    为了让用户方便、快捷、可靠的操作计算机硬件并执行自己的程序,操作系统提供了用户接口
    操作系统提供的接口分为两类:命令接口和程序接口
    • 命令接口:用户可以直接使用的,利用这些操作命令来组织和控制作业的执行。命令接口分为两类:联机命令接口和脱机命令接口,用户可以直接调用
      • 联机命令接口:又称交互式命令接口,适用于分时或实时系统的接口,由一组键盘操作命令组成。用户输入一条指令,操作系统就执行一条指令;例如:CMD
      • 脱机命令接口:又称批处理接口,使用于批处理系统,由一组作业控制命令组成。用户输入一堆指令,操作系统运行一堆指令。在操作系统运行这些命令时用户不可干预。例如:.bat文件
    • 程序接口:用户通过程序间接使用的,编程人员可以使用它们来请求操作系统服务
      • 程序接口:由一组系统调用(也称广义指令)组成
      • 用户通过在程序中使用这些系统调用来请求操作系统为其提供服务,只能通过用户程序间接调用
      • 如使用各种外部设备、申请分配和回收内存及其它各种要求
      • 比如常见的图形用户界面程序接口GUI

操作系统的分类

按照系统功能分类,分为以下几类:

  1. 批处理操作系统:多用于早期的计算机,将作业一次性提交给系统,然后由系统成批的处理
  2. 分时操作系统:将CPU的时间分成很小的时间片,按时间片轮转法分配给多个终端用户使用的操作系统。UNIX就是典型代表。
  3. 实时操作系统:对于特定的输入,系统能在极短的时间内做出响应,并完成对该输入请求处理的系统。主要用在生产过程自动处理的行业。如售票系统,航天发射系统、生产过程自动控制领域。具有实时性、可靠性的特点。但是实时系统一般是专用的,交互性比较差。
  4. 分布式操作系统: 通过计算机网络,将分布在不同位置的计算机互连起来,实现信息交换or资源共享。其基本特征为:功能和任务的分布性、高可靠性。
  5. 网络操作系统:除一般操作系统的基本功能外,还提供网络服务功能和管理。
  6. 嵌入式操作系统:发展非常快的领域。能运行在嵌入式系统中,对整个嵌入式系统以及它控制的各种资源进行统一管理和调度的操作系统。嵌入式操作系统能有效管理复杂的系统资源,具有实时高效性、软件固态化以及应用专业化等特点。

四、处理机的态及分类

所谓处理机的态,又称处理机的特权级,就是处理机当前处于何种状态,正在执行哪类程序。
操作系统的管理程序和用户程序在处理机上执行时,二者的职责不同,权限也不同,为了保护操作系统,所以要区分处理机的态。
基本的处理机的态是管态和用户态。

  • 管态:又称系统态,是操作系统的管理程序执行时机器所处的状态。在管态状态下,中央处理机可以使用全部机器指令,包括一组特权指令,可以使用所有的资源,允许访问整个存储区。
  • 用户态:又称目态,是用户程序执行时机器所处的状态。在用户态状态下,禁止使用特权指令,不能直接取用资源与改变及其状态,并且只允许用户程序访问自己的存储区域。

从目态转换为管态的唯一途径是中断。
从管态到目态可以通过修改程序状态字来实现,这将伴随这由操作系统程序到用户程序的转换。

五、特权指令

在核态下系统可以操作所有系统指令,一组特权指令主要涉及以下几个方面:

  • 改变机器状态的指令
  • 修改特殊寄存器的指令
  • 设计外部设备的输入/输出指令

特权级(Ring)也叫(hierarchical protection domains),有的也称为用户态(user mode)。它是一种机制来保护数据和阻止恶意行为(确保计算机安全)。电脑操作系统提供不同权限访问级别的资源。特权级分为4级,特权级0、1、2、3。
在windows中只使用特权级0和特权级3。特权最高的一般是特权级0,可以直接操作硬件,如CPU和内存。一般操作系统和驱动运行在此级别下。特权级3是给一般的程序使用的,可以调用基本的CPU指令。在特权级三无法调用特权级0的指令,如果调用则显示为非法指令。
引用特权级的概念是为了保护计算机,一些危险指令只有操作系统可以执行,防止普通程序滥用其他程序的资源。如间谍软件要想开启摄像头就必须向特权级0的驱动程序请求开启,否则就不允许。
中断门、调用门之类的。当然,也可以直接写一个驱动,因为驱动一般是ring0级别的,所以,只要驱动被加载,就意味着进入了ring0.
在系统的表象上看,我们打开任务管理器,可以看到一个名称为“System”的进程,这个事实上就是ring0的进程。所有的驱动都显示为在这个进程中,所有的驱动中创建的系统线程都是在这个进程中。表面上看,好像是ring3的进程,事实上,它是工作在ring0的。

六、两种程序

两种程序:

  1. 内核程序。操作系统的内核程序是系统的管理者,既可以执行特权指令,也可以执行非特权指令,运行在核心态。
  2. 应用程序。为了保证系统能安全运行,普通应用程序只能执行非特权指令,运行在用户态。

七、操作系统内核


内核是计算机上配置的底层软件,是操作系统最基本、最核心的部分。实现操作系统内核功能的那些程序就是内核程序。

八、操作系统体系结构


类比:操作系统的体系结构问题与企业的管理问题很相似。内核就是企业的管理层,负责一些重要的工作。只有管理层才能执行特权指令,普通员工只能执行非特权指令。用户态、核心态之间的切换相当于普通员工和管理层之间的工作交接。
大内核:企业初创时体量不大,管理层的人会负责大部分的事情。优点是效率高。缺点是组织结构混乱,难以维护。
微内核:随着企业体量越来越大,管理层只负责最核心的一些工作。优点是组织结构清晰,方便维护。缺点是效率低。

举例:应用程序想要请求操作系统的服务,这个服务的处理同时涉及到进程管理、存储管理、设备管理,大内核和微内核变态次数如下图:

注意:变态的过程是有成本的,要消耗不少时间,频繁地变态会降低系统性能

九、中断

中断的概念

中断的本质是发生中断就意味着需要操作系统介入,开展管理工作。CPU 在中断发生时暂时停下现行程序的执行,转向为临时发生的事件进行处理,处理完后,再返回执行原程序。中断是一种在发生了一个外部的事件时调用相应的处理程序(或称服务程序)的过程。中断服务程序与中断时CPU正在运行的程序是相互独立的,相互不传递数据。

  1. 当中断发生时,CPU立即进入核心态
  2. 当中断发生后,当前运行的进程暂停运行,并由操作系统内核对中断进行处理
  3. 对于不同的中断信号,会进行不同的处理

发生了中断,就意味着需要操作系统介入,开展管理工作。由于操作系统的管理工作(比如进程切换、分配I/O设备等)需要使用特权指令,因此CPU要从用户态转为核心态。中断可以使CPU从用户态切换为核心态,使操作系统获得计算机的控制权。有了中断,才能实现多道程序并发执行。

用户态、核心态之间的切换是怎么实现的?
答:“用户态→核心态”是通过中断实现的。并且中断是唯一途径。“核心态→用户态”的切换是通过执行一个特权指令,将程序状态字(PSW)的标志位设置为“用户态”。
内核态→用户态:执行一条特权指令--修改PSW的标志位为“用户态”,这个动作意味着操作系统将主动让出CPU使用权
用户态→内核态:由“中断”引发,硬件自动完成变态过程,触发中断信号意味着操作系统将强行夺回CPU的使用权

中断的类型


大多数的教材、试卷中,“中断”特指狭义的中断,即外中断。而内中断一般称为“异常。

  • 内中断:发生在主机内部的中断称为内中断,也称为异常
  • 外中断:由主机外部事件引起的中断称外中断

中断的例子:
内部中断(异常处理):算术操作异常、非法指令、越权指令、页面失效、试图在用户态下执行特权指令、执行除法指令时发现除数为0
外部中断(可屏蔽,不可屏蔽):I/O中断--由输入/输出设备(键盘、鼠标、电源)发来的中断号、时钟中断--由时钟部件发来的中断信号

中断机制的基本原理

不同的中断信号,需要用不同的中断处理程序来处理。当CPU检测到中断信号后,会根据中断信号的类型去查询“中断向量表”,以此来找到相应的中断处理程序在内存中的存放位置。

十、系统调用

系统调用及其作用

操作系统作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要包括命令接口和程序接口。其中,程序接口由一组系统调用组成。

“系统调用”是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以发出系统调用请求来获得操作系统的服务。

应用程序通过系统调用请求操作系统的服务。系统中的各种共享资源都由操作系统统一掌管,因此在用户程序中,凡是与资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统提出服务请求,由操作系统代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作。

系统调用和库函数的区别

系统调用背后的过程

第二章

一、进程的定义、组成、组织方式、特征

进程的定义

程序:就是一个指令序列。早期的计算机只支持单道程序。

进程的组成

进程的组织

在一个系统中,通常有数十、数百乃至数千个PCB。为了能对他们加以有效的管理,应该用适当的方式把这些PCB组织起来。
注:进程的组成讨论的是一个进程内部由哪些部分构成的问题,而进程的组织讨论的是多个进程之间的组织方式问题

链接方式

索引方式

进程的特征

程序是静态的,进程是动态的,相比于程序,进程拥有以下特征:

二、进程的状态

三种基本状态(运行、就绪、阻塞)

进程是程序的一次执行。在这个执行过程中,有时进程正在被CPU处理,有时又需要等待CPU服务,可见进程的状态是会有各种变化。为了方便对各个进程的管理,操作系统需要将进程合理地划分为几种状态。

另外两种状态(创建、终止)

  1. 创建态

  1. 终止态

进程状态之间的转换

三、进程的控制

进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。简化理解:反正进程控制就是要实现进程状态转换。

用原语实现进程控制。原语的特点是执行期间不允许中断,只能一气呵成。这种不可被中断的操作即原子操作。原语采用“关中断指令”和“开中断指令”实现。

显然,关/开中断指令的权限非常大,必然是只允许在核心态下执行的特权指令

进程控制相关的原语

进程控制会导致进程状态的转换。无论哪个原语,要做的无非三类事情:

  1. 更新PCB中的信息(如修改进程状态标志、将运行环境保存到PCB、从PCB恢复运行环境)
    a. 所有的进程控制原语一定都会修改进程状态标志
    b. 剥夺当前运行进程的CPU使用权必然需要保存其运行环境
    c. 某进程开始运行前必然要恢复期运行环境
  2. 将PCB插入合适的队列
  3. 分配/回收资源

进程的创建原语

进程的终止原语

进程的唤醒和阻塞原语

  1. 进程的阻塞和唤醒原语是成对存在的,必须成对使用。
  2. 阻塞原语是由被阻塞进程自我调用实现的
  3. 唤醒原语是由一个被唤醒进程合作或被其他相关的进程调用实现的

进程的切换原语

四、进程的通信

进程通信就是指进程之间的信息交换。进程是系统分配资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。
为了保证安全,一个进程不能直接访问另一个进程的地址空间。但是进程之间的信息交换又是必须实现的。为了保证进程间的安全通信,操作系统提供了一些方法。

  1. 共享存储
  2. 消息传递
  3. 管道通信

共享存储

消息传递

管道通信

五、线程和多线程

什么是线程

线程的属性

线程的实现方式

用户级线程

内核级线程

二者结合

多线程模型

一对一模型

多对一模型

多对多模型

六、处理机调度

基本概念

当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序,这就是“调度”研究的问题。
在多道程序系统中,进程的数量往往是多于处理机的个数的,这样不可能同时并行地处理各个进程。处理机调度,就是从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程的并发执行。

调度的三个层次

高级调度(作业调度)

由于内存空间有限,有时无法将用户提交的作业全部放入内存,因此就需要确定某种规则来决定将作业调入内存的顺序。
高级调度(作业调度)。按一定的原则从外存上处于后备队列的作业中挑选一个(或多个)作业,给他们分配内存等必要资源,并建立相应的进程(建立PCB),以使它(们)获得竞争处理机的权利。
高级调度是辅存(外存)与内存之间的调度。每个作业只调入一次,调出一次。作业调入时会建立相应的PCB,作业调出时才撤销PCB。高级调度主要是指调入的问题,因为只有调入的时机需要操作系统来确定,但调出的时机必然是作业运行结束才调出。

中级调度(内存调度)

引入了虚拟存储技术之后,可将暂时不能运行的进程调至外存等待。等它重新具备了运行条件且内存又稍有空闲时,再重新调入内存。这么做的目的是为了提高内存利用率和系统吞吐量。暂时调到外存等待的进程状态为挂起状态。值得注意的是,PCB并不会一起调到外存,而是会常驻内存。PCB中会记录进程数据在外存中的存放位置,进程状态等信息,操作系统通过内存中的PCB来保持对各个进程的监控、管理。被挂起的进程PCB会被放到的挂起队列中。
中级调度(内存调度),就是要决定将哪个处于挂起状态的进程重新调入内存。一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高

补充知识:进程的挂起态与七状态模型

暂时调到外存等待的进程状态为挂起状态(挂起态,suspend)
挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态
五状态模型 >七状态模型

低级调度(进程调度)

低级调度(进程调度),其主要任务是按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。
进程调度的频率很高,一般几十毫秒一次。

三层调度的联系和对比

进程调度的时机

进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机。

进程调度的方式

  • 有的系统中,只允许进程主动放弃处理机
  • 有的系统中,进程可以主动放弃处理机,当有更紧急的任务需要处理时,也会强行剥夺处理机(被动放弃)
  • 基于以上两点,进程调度的方式分为剥夺调度方式,非剥夺调度方式

进程的切换和过程

“狭义的进程调度”与“进程切换”的区别:

  • 狭义的进程调度指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程,也可能是另一个进程,后一种情况就需要进程切换)
  • 进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程。

广义的进程调度包含了选择一个进程和进程切换两个步骤。

进程切换的过程主要完成了:

  1. 对原来运行进程各种数据的保存
  2. 对新的进程各种数据的恢复
    (如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)

注意:进程切换是有代价的,因此如果过于频繁的进行进程调度、切换,必然会使整个系统的效率降低使系统大部分时间都花在了进程切换上,而真正用于执行进程的时间减少。

调度算法的评价指标

  1. CPU利用率

  1. 系统吞吐量

  1. 周转时间

  1. 等待时间

  1. 响应时间

调度算法

  1. 先来先服务——FCFS

  1. 短作业有限——SJF

  1. 高响应比优先—HRRN

  1. 时间片轮转—RR

  1. 优先级调度算法

  1. 多级反馈队列调度算法

七、进程同步、互斥

补充

并发、并行、同步、异步的区别

并发与并行

  • 并发是指在同一时间段内,多个程序或任务交替执行,但任一时刻只有一个任务在执行。
  • 并行则是指多个任务在同一时刻同时执行。

在操作系统中,并发是通过时间片轮转等方式实现的,而并行则需要硬件支持,如多核处理器。

同步与异步

  • 同步是指多个任务之间需要相互等待,一个任务需要等待另一个任务完成后才能继续执行。 同步的目的是为了保证数据的一致性和完整性。
  • 异步则是指任务之间不需要相互等待,一个任务的执行不会阻塞其他任务的执行。

同步和异步描述的是程序执行过程中的协作方式。

概念

  1. 同步

知识点回顾:进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。

读进程和写进程并发地运行,由于并发必然导致异步性,因此“写数据”和“读数据”两个操作执行的先后顺序是不确定的。而实际应用中,又必须按照“写数据→读数据”的顺序来执行的。如何解决这种异步问题,就是“进程同步”所讨论的内容。

同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。

  1. 互斥

进程的“并发”需要“共享”的支持。各个并发执行的进程不可避免的需要共享一些系统资源(比如内存,又比如打印机、摄像头这样的I/0设备)

我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。对临界资源的访问,必须互斥地进行。
互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。

对临界资源的互斥访问,可以在逻辑上分为如下四个部分:

注意:临界区是进程中访问临界资源的代码段。进入区和退出区是负责实现互斥的代码段。临界区也可称为“临界段”。

为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:

  • 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
  • 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
  • 有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);
  • 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。

进程互斥的软件实现方法

  1. 单标志法

算法思想:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予

turn 的初值为0,即刚开始只允许0号进程进入临界区。若P1先上处理机运行,则会一直卡在⑤。直到 P1的时间片用完,发生调度,切换 P0 上处理机运行。代码①不会卡住P0,P0可以正常访问临界区,在P0访问临界区期间即时切换回P1,P1依然会卡在⑤只有P0在退出区将 turn 改为1后,P1才能进入临界区。
turn 表示当前允许进入临界区的进程号,而只有当前允许进入临界区的进程在访问了临界区之后,才会修改 turn 的值。也就是说,对于临界区的访问,一定是按P0→P1→P0→P1→…这样轮流访问这种必须“轮流访问”带来的问题是,如果此时允许进入临界区的进程是P0,而P0一直不访问临界区,那么虽然此时临界区空闲,但是并不允许P1访问。因此,单标志法存在的主要问题是:违背“空闲让进”原则。

  1. 双标志先检查法

算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿,比如“flag[0]=ture”意味着0号进程P0现在想要进入临界区。每个进程在进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应的标志flag[i]设为true,之后开始访问临界区

若按照 ➄➁➅➂⑦...的顺序执行,P0 和 P1将会同时访问临界区。因此,双标志先检查法的主要问题是:违反“忙则等待”原则。原因在于,进入区的“检查”和“上锁”两个处理不是一气呵成的。“检查”后,“上锁”前可能发生进程切换。

  1. 双标志后检查法

算法思想:双标志先检查法的改版。前一个算法的问题是先“检查”后“上锁”,但是这两个操作又无法一气呵成,因此导致了两个进程同时进入临界区的问题。因此,人们又想到先“上锁”后“检查”的方法,来避免上述问题。

若按照 ①⑤➁➅.的顺序执行,P0 和 P1将都无法进入临界区因此,双标志后检查法虽然解决了“忙则等待”的问题,但是又违背了“空闲让进”和“有限等待”原则,会因各进程都长期无法访问临界资源而产生“饥饿”现象。两个进程都争着想进入临界区,但是谁也不让谁,最后谁都无法进入临界区。

  1. Peterson算法

算法思想:双标志后检查法中,两个进程都争着想进入临界区,但是谁也不让谁,最后谁都无法进入临界区。GaryL.Peterson想到了一种方法,如果双方都争着想进入临界区,那可以让进程尝试“孔融让梨”,主动让对方先使用临界区。

进程互斥的硬件实现方法

  1. 中断屏蔽方法

  1. TestAndSet指令

  1. Swap指令

信号量机制

概念

整型信号量

记录型信号量

信号量实现进程的互斥、同步、前驱关系

  1. 信号量机制实现进程互斥

  1. 信号量机制实现进程同步

  1. 信号量机制实现前驱关系

生产者消费者问题

多生产者多消费者问题

吸烟者问题

读者写者问题

哲学家进餐问题

三种解决方案

管程

概念

管程是一种特殊的软件模块,有这些部分组成:

  1. 局部于管程的共享数据结构说明;
  2. 对该数据结构进行操作的一组过程;(“过程”其实就是“函数”)
  3. 对局部于管程的共享数据设置初始值的语句;
  4. 管程有一个名字。

管程的基本特征:

  1. 局部于管程的数据只能被局部于管程的过程所访问:
  2. 一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
  3. 每次仅允许一个进程在管程内执行某个内部过程

用管程解决生产者消费者问题

死锁

概念

在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象,就是“死锁”,发生死锁后若无外力干涉这些进程都将无法向前推进。

死锁、饥饿、死循环的区别

死锁产生的必要条件

什么时候会产生死锁

  1. 对系统资源的竞争。各进程对不可剥夺的资源(如打印机)的竞争可能引起死锁,对可剥夺的资源(CPU)的竞争是不会引起死锁的。
  2. 进程推进顺序非法。请求和释放资源的顺序不当,也同样会导致死锁。例如,并发执行的进程P1、P2分别申请并占有了资源 R1、R2,之后进程P1又紧接着申请资源R2,而进程P2又申请资源R1,两者会因为申请的资源被对方占有而阻塞,从而发生死锁。
  3. 信号量的使用不当也会造成死锁。如生产者-消费者问题中,如果实现互斥的P操作在实现同步的P操作之前,就有可能导致死锁。(可以把互斥信号量、同步信号量也看做是一种抽象的系统资源)

死锁的处理策略

  1. 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
  2. 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)。
  3. 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。

死锁的处理策略

预防死锁(静态策略)
  1. 破坏互斥条件

互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁。
如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如:SPOOLing技术。操作系统可以采用 SPO0Ling 技术把独占设备在逻辑上改造成共享设备。比如,用SPOOLing技术将打印机改造为共享设备….

该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方还必须保护这种互斥性。因此,很多时候都无法破坏互斥条件。

  1. 破坏不剥夺条件

不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。

破坏不剥夺条件:
方案一:当某个进程请求新的资源得不到满足时,它必须立即释放保持的所有资源,待以后需要时再重新申请。也就是说,即使某些资源尚未使用完,也需要主动释放,从而破坏了不可剥夺条件。
方案二:当某个进程需要的资源被其他进程所占有的时候,可以由操作系统协助,将想要的资源强行剥夺。这种方式一般需要考虑各进程的优先级(比如:剥夺调度方式,就是将处理机资源强行剥夺给优先级更高的进程使用)

该策略的缺点:
1.实现起来比较复杂。
2.释放已获得的资源可能造成前一阶段工作的失效。因此这种方法一般只适用于易保存和恢复状态的资源,如CPU。
3.反复地申请和释放资源会增加系统开销,降低系统吞吐量。
4.若采用方案一,意味着只要暂时得不到某个资源,之前获得的那些资源就都需要放弃,以后再重新申请。如果一直发生这样的情况,就会导致进程饥饿。

  1. 破坏请求和保持条件

请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。

可以采用静态分配方法,即进程在运行前一次申请完它所需要的全部资源,在它的资源未满足前,不让它投入运行。一旦投入运行后,这些资源就一直归它所有,该进程就不会再请求别的任何资源

该策略实现起来简单,但也有明显的缺点:有些资源可能只需要用很短的时间,因此如果进程的整个运行期间都一直保持着所有资源,就会造成严重的资源浪费,资源利用率极低。另外,该策略也有可能导致某些进程饥饿。

  1. 破坏循环等待条件

循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下个进程所请求。

可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源(即编号相同的资源)一次申请完。
原理分析:一个进程只有已占有小编号的资源时,才有资格申请更大编号的资源。按此规则,已持有大编号资源的进程不可能逆向地回来申请小编号的资源,从而就不会产生循环等待的现象。

该策略的缺点:
1.不方便增加新的设备,因为可能需要重新分配所有的编号;
2.进程实际使用资源的顺序可能和编号递增顺序不一致,会导致资源浪费;
3.必须按规定次序申请资源,用户编程麻烦

避免死锁(动态策略)
  • 什么是安全序列

  • 银行家算法

算法流程

案例

死锁的检测和解除(允许死锁发生)

如果系统中既不采取预防死锁的措施,也不采取避免死锁的措施,系统就很可能发生死锁。在这种情况下,系统应当提供两个算法:
①死锁检测算法:用于检测系统状态,以确定系统中是否发生了死锁。
②死锁解除算法:当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来。

  • 死锁的检测

为了能对系统是否已发生了死锁进行检测,必须:
①用某种数据结构来保存资源的请求和分配信息;
②提供一种算法,利用上述信息来检测系统是否已进入死锁状态

如果系统中剩余的可用资源数足够满足进程的需求,那么这个进程暂时是不会阻塞的,可以顺利地执行下去。如果这个进程执行结束了把资源归还系统,就可能使某些正在等待资源的进程被激活,并顺利地执行下去。相应的,这些被激活的进程执行完了之后又会归还一些资源,这样可能又会激活另外一些阻塞的进程...

如果按上述过程分析,最终能消除所有边,就称这个图是可完全简化的。此时一定没有发生死锁(相当于能找到一个安全序列);
如果最终不能消除所有边,那么此时就是发生了死锁。

检测死锁的算法:
1)在资源分配图中,找出既不阻塞又不是孤点的进程Pi(即找出一条有向边与它相连,且该有向边对应资源的申请数量小于等于系统中已有空闲资源数量。如下图中,R1没有空闲资源,R2有一个空闲资源。若所有的连接该进程的边均满足上述条件,则这个进程能继续运行直至完成,然后释放它所占有的所有资源)。消去它所有的请求边和分配变,使之称为孤立的结点。在下图中P1是满足这一条件的进程结点,于是将P1的所有边消去。2)进程 Pi所释放的资源,可以唤醒某些因等待这些资源而阻塞的进程,原来的阻塞进程可能变为非阻塞进程。在下图中,P2就满足这样的条件。根据1)中的方法进行一系列简化后,若能消去途中所有的边,则称该图是可完全简化的。

  • 死锁的解除

一旦检测出死锁的发生,就应该立即解除死锁。

补充:并不是系统中所有的进程都是死锁状态,用死锁检测算法化简资源分配图后,还连着边的那些进程就是死锁进程。

解除死锁的主要方法有:
1.资源剥夺法。挂起(暂时放到外存上)某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但是应防止被挂起的进程长时间得不到资源而饥饿。
2.撤销进程法(或称终止进程法)。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。这种方式的优点是实现简单,但所付出的代价可能会很大。因为有些进程可能已经运行了很长时间,已经接近结束了,一旦被终止可谓功亏一,以后还得从头再来。
3.进程回退法。让一个或多个死锁进程回退到足以避免死锁的地步。这就要求系统要记录进程的历史信息,设置还原点。

第三章

一、内存的基本知识

内存是用于存放数据的硬件,程序执行前需要先放到内存中才能被CPU处理。

进程的运行原理-指令

我们写的代码要翻译成CPU能识别的指令。这些指令会告诉CPU应该去内存的哪个地址存/取数据这个数据应该做什么样的处理。

逻辑地址 vs 物理地址

从写程序到程序运行

装入模块装入内存

装入的三种方式

  1. 绝对装入

  1. 静态重定位

  1. 动态重定位

链接的三种方式

  1. 静态链接

  1. 装入时动态链接

  1. 运行时动态链接

二、内存的管理

操作系统作为系统资源的管理者,当然也需要对内存进行管理,要管些什么呢?

  1. 操作系统负责内存空间的分配与回收
  2. 操作系统需要提供某种技术从逻辑上对内存空间进行扩充
  3. 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换
  4. 操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰

内存空间的扩充

  1. 覆盖技术

覆盖技术,用来解决“程序大小超过物理内存总和”的问题

  1. 交换技术

交换(对换)技术的设计思想:内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)。

中级调度(内存调度),就是要决定将哪个处于挂起状态的进程重新调入内存。暂时换出外存等待的进程状态为挂起状态(挂起态,suspend)挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态。

内存空间的分配与回收

连续分配管理方式

连续分配:指为用户进程分配的必须是一个连续的内存空间

  1. 单一连续分配

  1. 固定分区分配

分区说明表

  1. 动态分区分配(可变分区分配)

系统要用什么样的数据结构纪录内存的使用情况?

当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

如何进行分区的分配与回收操作?

  • 内存分配的两种情况

  • 内存回收的四种情况

情况一

情况二

情况三

情况四

  1. 内部碎片与外部碎片

  1. 动态分区分配算法

  • 首次适应算法

算法思想:每次都从低地址开始查找,找到第一个能满足大小的空闲分区。

如何实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

  • 最佳适应算法

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区即,优先使用更小的空闲区。

如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种方法会产生很多的外部碎片。

  • 最坏适应算法

又称 最大适应算法(Largest Fit)

算法思想:为了解决最佳适应算法的问题——即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。

如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之后有“大进程”到达,就没有内存分区可用了。

  • 邻近适应算法

算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。

如何实现:空闲分区以地址递增的顺序排列(可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

首次适应算法每次都要从头查找,每次都需要检索低地址的小分区但是这种规则也决定了当低地址部分有更小的分区可以满足需求时会更有可能用到低地址部分的小分区,也会更有可能把高地址部分的大分区保留下来(最佳适应算法的优点)

邻近适应算法的规则可能会导致无论低地址、高地址部分的空闲分区都有相同的概率被使用,也就导致了高地址部分的大分区更可能被使用,划分为小分区,最后导致无大分区可用(最大适应算法的缺点)综合来看,四种算法中,首次适应算法的效果反而更好

非连续分配管理方式

连续分配:为用户进程分配的必须是一个连续的内存空间。
非连续分配:为用户进程分配的可以是一些分散的内存空间。

  1. 基本分页存储管理

地址转换方式

逻辑地址结构

页表

基本地址变换机构

具有快表的地址变换结构

  • 局部性原理

  • 快表

快表,又称联想寄存器(TLB,translation lookaside buffer),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度与此对应,内存中的页表常称为慢表。

引入快表后,地址的转换过程

两级页表

  1. 基本分段存储管理

分段

进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址内存;

分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

分段系统的逻辑地址结构由段号(段名)和段内地址(段内偏移量)所组成。如:

段号的位数决定了每个进程最多可以分几个段
段内地址位数决定了每个段的最大长度是多少

在上述例子中,若系统是按字节寻址的,则段号占16位,因此在该系统中,每个进程最多有2^16=64K个段,段内地址占 16位,因此每个段的最大长度是2^16=64KB。

段表

地址变换

分段、分页管理的对比

访问一个逻辑地址需要几次访存?
分页(单级页表):第一次访存——查内存中的页表,第二次访存——访问目标内存单元。总共两次访存。
分段:第一次访存——查内存中的段表,第二次访存——访问目标内存单元。总共两次访存。
与分页系统类似,分段系统中也可以引入快表机构,将近期访问过的段表项放到快表中,这样可以少一次访问,加快地址变换速度。

  1. 段页式存储管理

分页、分段的优缺点分析

分段+分页=段页式管理

段页式管理的逻辑地址结构

段表、页表

逻辑地址转换为物理地址

三、虚拟内存

虚拟内存的基本概念

传统存储管理方式的特征、缺点

局部性原理

虚拟内存的定义和特征

如何实现虚拟内存技术

虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内存管理方式基础上。

请求分页管理方式

请求分页与基本分页的主要区别

页表机制

缺页中断机构

缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断。

一条指令在执行期间,可能产生多次缺页中断。(如:copyAtoB,即将逻辑地址A中的数据复制到逻辑地址B,而A、B属于不同的页面,则有可能产生两次中断)。

地址变换机构

页面置换算法

  1. 最佳置换算法(OPT)

最佳置换算法(OPT,Optimal):每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。

最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。

  1. 先进先出置换算法(FIFO)

先进先出置换算法(FIFO):每次选择淘汰的页面是最早进入内存的页面。

实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。队列的最大长度取决于系统为进程分配了多少个内存块。

Belady 异常 —— 当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。

只有 FIFO 算法会产生 Belady 异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差。

  1. 最近最久未使用置换算法(LRU)

最近最久未使用置换算法(LRU,leastrecentlyused):每次淘汰的页面是最近最久未使用的页面。

实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。

该算法的实现需要专门的硬件支持,虽然算法性能好,但是实现困难,开销大。

  1. 时钟置换算法(CLOCK)

最佳置换算法性能最好,但无法实现;先进先出置换算法实现简单,但算法性能差;最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,算法开销大。

时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,NotRecently Used)

简单的 CLOCK 算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)

举例:一个作业物理块数为3,作业页面走向为3,4,2,6,4,3。红色为访问位,蓝色为内存数据。

  1. 改造型时钟置换算法

页面分配策略

页面分配、置换策略

第四章

一、文件管理

文件的属性

文件名:由创建文件的用户决定文件名,主要是为了方便用户找到文件,同一目录下不允许有重名文件;
标识符:一个系统内的各文件标识符唯一,对用户来说毫无可读性,因此标识符只是操作系统用于区分各个文件的一种内部名称;
类型:指明文件的类型;
位置:文件存放的路径(让用户使用)、在外存中的地址(操作系统使用,对用户不可见)
大小:指明文件大小;
创建时间、上次修改时间;
文件所有者信息;
保护信息:对文件进行保护的访问控制信息。

文件的逻辑结构

目录结构

操作系统向上提供的功能

文件的物理结构

操作系统需要提供的其他文件管理功能

  • 文件共享
  • 文件保护

文件的逻辑结构

按文件是否有结构分类,可以分为无结构文件、有结构文件两种。

无结构文件

无结构文件:文件内部的数据就是一系列二进制流或字符流组成。又称“流式文件”。如:Windows 操作系统中的 .txt 文件。

有结构文件

有结构文件:由一组相似的记录组成,又称“记录式文件”。每条记录又若干个数据项组成。如:数据库表文件。一般来说,每条记录有一个数据项可作为关键字(作为识别不同记录的ID)。根据各条记录的长度(占用的存储空间)是否相等,又可分为定长记录和可变长记录两种。

  1. 顺序文件

顺序文件:文件中的记录一个接一个地顺序排列(逻辑上),记录可以是定长的或可变长的。各个记录在物理上可以顺序存储或链式存储。

  1. 索引文件

索引表本身是定长记录的顺序文件。因此可以快速找到第i个记录对应的索引项。可将关键字作为索引号内容,若按关键字顺序排列,则还可以支持按照关键字折半查找。每当要增加/删除一个记录时,需要对索引表进行修改。由于索引文件有很快的检索速度,因此主要用于对信息处理的及时性要求比较高的场合。另外,可以用不同的数据项建立多个索引表。

  1. 索引顺序文件

索引文件的缺点:每个记录对应一个索引表项,因此索引表可能会很大。比如:文件的每个记录平均只占8B,而每个索引表项占32个字节,那么索引表都要比文件内容本身大4倍,这样对存储空间的利用率就太低了。

索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是,并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项。

  1. 多级索引顺序文件

为了进一步提高检索效率,可以为顺序文件建立多级索引表。例如,对于一个含 10^6个记录的文件,可先为该文件建立一张低级索引表,每100个记录为一组,故低级索引表中共有 10000 个表项(即10000个定长记录),再把这 10000 个定长记录分组,每组100个,为其建立顶级索引表,故顶级索引表中共有 100 个表项。

文件目录

文件控制块

需要对目录进行哪些操作?
搜索:当用户要使用一个文件时,系统要根据文件名搜索目录,找到该文件对应的目录项;
创建文件:创建一个新文件时,需要在其所属的目录中增加一个目录项;
删除文件:当删除一个文件时,需要在目录中删除相应的目录项;
显示目录:用户可以请求显示目录的内容,如显示该目录中的所有文件及相应属性;
修改目录:某些文件属性保存在目录中,因此这些属性变化时需要修改相应的目录项(如:文件重命名)

单级目录结构

早期操作系统并不支持多级目录,整个系统中只建立一张目录表,每个文件占一个目录项。

单级目录实现了“按名存取”,但是不允许文件重名。
在创建一个文件时,需要先检查目录表中有没有重名文件,确定不重名后才能允许建立文件,并将新文件对应的目录项插入目录表中。
显然,单级目录结构不适用于多用户操作系统。

两级目录结构

早期的多用户操作系统,采用两级目录结构。分为主文件目录(MFD,Master File Directory)和用户文件目录(UFD,User Flie Directory)。

多级目录结构(树形目录结构)

用户(或用户进程)要访问某个文件时要用文件路径名标识文件,文件路径名是个字符串。各级目录之间用“/”隔开。从根目录出发的路径称为绝对路径。例如:自拍.jpg的绝对路径是“/照片/2015-08/自拍.jpg”系统根据绝对路径一层一层地找到下一级目录。刚开始从外存读入根目录的目录表;找到“照片”目录的存放位置后,从外存读入对应的目录表:再找到“2015-08”目录的存放位置,再从外存读入对应目录表:最后才找到文件“自拍.jpg”的存放位置。整个过程需要3次读磁盘I/0操作。很多时候,用户会连续访问同一目录内的多个文件(比如:接连査看“2015-08"目录内的多个照片文件),显然,每次都从根目录开始查找,是很低效的。因此可以设置一个“当前目录”。

在 Linux 中,表示当前目录,因此如果“照片”是当前目录,则"自拍jpg"的相对路径为:“./2015-08/自拍.jpg”。从当前路径出发,只需要查询内存中的“照片”目录表,即可知道"2015-08"目录表的存放位置,从外存调入该目录,即可知道“自拍jpg”存放的位置了。“当前目录”和“相对路径”后,磁盘I/0的次数减少了,这就提升了访问文件的效率。

树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护。但是,树形结构不便于实现文件的共享。为此,提出了“无环图目录结构”。

无环图目录结构

可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一日录下的所有内容)需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。用户提出删除结点的请求时,只是删除该用户的FCB、并使共享计数器减1,并不会直接删除共享结点。只有共享计数器减为0时,才删除结点。

注意:共享文件不同于复制文件。在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有用户都可以看到文件数据的变化。

索引结点

当找到文件名对应的目录项时,才需要将索引结点调入内存,索引结点中记录了文件的各种信息,包括文件在外存中的存放位置,根据“存放位置”即可找到文件。存放在外存中的索引结点称为“磁盘索引结点”,当索引结点放入内存后称为“内存索引结点”相比之下内存索引结点中需要增加一些信息,比如:文件是否被修改、此时有几个进程正在访问该文件等。

文件的物理结构

文件块、磁盘块

连续分配

连续分配方式要求每个文件在磁盘上占有一组连续的块。

用户给出要访问的逻辑块号,操作系统找到该文件对应的目录项(FCB)...
物理块号=起始块号+逻辑块号,当然,还需要检查用户提供的逻辑块号是否合法(逻辑块号>长度就不合法)

可以直接算出逻辑块号对应的物理块号,因此连续分配支持顺序访问和直接访问(即随机访间)

读取某个磁盘块时,需要移动磁头。访问的两个磁盘块相隔越远,移动磁头所需时间就越长。
结论:连续分配的文件在顺序读/写时速度最快

链接分配

链接分配采取离散分配的方式,可以为文件分配离散的磁盘块。分为隐式链接和显式链接两种。

  1. 隐式链接

结论:采用隐式链接的链接分配方式,很方便文件拓展,另外,所有的空闲磁盘块都可以被利用,不会有碎片问题,外存利用率高。

  1. 显式链接

把用于链接文件各物理块的指针显式地存放在一张表中。即 文件分配表(FAT, File Allocation Table)。

假设某个新创建的文件“aaa”依次存放在磁盘块2→5→0→1
假设某个新创建的文件“bbb”依次存放在磁盘块4→23→3
注意:一个磁盘仅设置一张FAT开机时,将FAT读入内存,并常驻内存。 FAT 的各个表项在物理上连续存储,且每一个表项长度相同,因此“物理块号”字段可以是隐含的。

如何实现文件的逻辑块号到物理块号的转变?

用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB)...
从目录项中找到起始块号,若i>0,则查询内存中的文件分配表FAT,往后找到i号逻辑块对应的物理块号。逻辑块号转换成物理块号的过程不需要读磁盘操作

结论:采用链式分配(显式链接)方式的文件,支持顺序访问,也支持随机访问(想访问i号逻辑块时,并不需要依次访问之前的0~i-1号逻辑块),由于块号转换的过程不需要访问磁盘,因此相比于隐式链接来说,访问速度快很多。显然,显式链接也不会产生外部碎片,也可以很方便地对文件进行拓展。

索引分配

索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块(索引表的功能类似于内存管理中的页表--建立逻辑页面到物理页之间的映射关系)。索引表存放的磁盘块称为索引块。文件数据存放的磁盘块称为数据块。

假设某个新创建的文件“aaa”的数据依次存放在磁盘块2→5→13→9。7号磁盘块作为“aaa”的索引块,索引块中保存了索引表的内容。

注:在显式链接的链式分配方式中,文件分配表 FAT 是一个磁盘对应一张。而索引分配方式中,索引表是一个文件对应一张。
可以用固定的长度表示物理块号(如:假设磁盘总容量为1TB=2^40B,磁盘块大小为1KB,则共有 230个磁盘块,则可用4B表示磁盘块号),因此,索引表中的“逻辑块号”可以是隐含的。

如何实现文件的逻辑块号到物理块号的转换?

用户给出要访问的逻辑块号i,操作系统找到该文件对应的目录项(FCB)...
从目录项中可知索引表存放位置,将索引表从外存读入内存,并查找索引表即可只i号逻辑块在外存中的存放位置。
可见,索引分配方式可以支持随机访问文件拓展也很容易实现(只需要给文件分配一个空闲块,并增加一个索引表项即可)但是索引表需要占用一定的存储空间。

若每个磁盘块1KB,一个索引表项4B,则一个磁盘块只能存放 256 个索引项。如果一个文件的大小超过了256块,那么一个磁盘块是装不下文件的整张索引表的,如何解决这个问题?

① 链接方案

如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放。

② 多层索引

建立多层索引(原理类似于多级页表)。使第一层索引块指向第二层的索引块。还可根据文件大小的要求再建立第三层、第四层索引块。

③ 混合索引

多种索引分配方式的结合。例如,一个文件的顶级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表)、还包含两级间接索引(指向两层索引表)。

总结

文件存储空间管理

存储空间的划分与初始化

空闲表法

适用于“连续分配方式”

空闲链表法

  1. 空闲盘块链

  1. 空闲盘区链

位示图法

成组链接法

空闲表法、空闲链表法不适用于大型文件系统,因为空闲表或空闲链表可能过大。UNIX系统中采用了成组链接法对磁盘空闲块进行管理。
文件卷的目录区中专门用一个磁盘块作为“超级块”当系统启动时需要将超级块读入内存。并且要保证内存与外存中的“超级块”数据一致。

文件的基本操作

创建文件

删除文件

打开文件

关闭文件

读文件

写文件

文件共享

操作系统为用户提供文件共享功能,可以让多个用户共享地使用同一个文件。

注意:多个用户共享同一个文件,意味着系统中只有“一份”文件数据。并且只要某个用户修改了该文件的数据,其他用户也可以看到文件数据的变化。如果是多个用户都“复制”了同一个文件,那么系统中会有“好几份”文件数据。其中一个用户修改了自己的那份文件数据,对其他用户的文件数据并没有影响。

基于索引结点的共享方式(硬链接)

基于符号链的共享方式(软链接)

文件保护

口令保护

加密保护

使用某个“密码”对文件进行加密,在访问文件时需要提供正确的“密码”才能对文件进行正确的解密。

优点:保密性强,不需要在系统中存储“密码”;
缺点:编码/译码,或者说加密/解密要花费一定时间。

访问控制

文件系统的层次结构

二、磁盘

磁盘的结构

磁盘、磁道、扇区

如何在磁盘中读/写数据

盘面、柱面

磁盘的物理地址

磁盘的分类

磁盘调度算法

一次磁盘读/写操作需要的时间

寻找时间(寻道时间)Ts:在读/写数据前,将磁头移动到指定磁道所花的时间。
①启动磁头臂是需要时间的。假设耗时为s;
②移动磁头也是需要时间的。假设磁头匀速移动,每跨越个磁道耗时为 m,总共需要跨越n条磁道。则:寻道时间Ts=s+m*n。
现在的硬盘移动一个磁道大约需要0.2ms,磁臂启动时间约为2ms。

延迟时间Tr:通过旋转磁盘,使磁头定位到目标扇区所需要的时间。设磁盘转速为r(单位:转/秒,或转/分),则平均所需的延迟时间T=(1/2)*(1/r)= 1/2r。
1/r 就是转一圈需要的时间。找到目标扇区平均需要转半圈,因此再乘以 1/2。硬盘的典型转速为 5400 转/分,或 7200 转/分。

传输时间Tt:从磁盘读出或向磁盘写入数据所经历的时间,假设磁盘转速为r,此次读/写的字节数为b,每个磁道上的字节数为 N。则:传输时间Tt=(1/r)*(b/N)= b/(rN)。
每个磁道要可存N字节的数据,因此b字节的数据需要 b/N 个磁道才能存储。而读/写一个磁道所需的时间刚好又是转一圈所需要的时间 1/r。

总的平均存取时间Ta=Ts + 1/2r + b / (rN)。

先来先服务(FCFS)

最短寻找时间优先算法(SSTF)

扫描算法(SCAN)

LOOK算法

循环扫描算法(C-SCAN)

C-LOOK算法

减少磁盘延迟时间的方法

交替编号

磁盘地址结构的设计

假设某磁盘有8个柱面/磁道(假设最内侧柱面/磁道号为0),4个盘面,8个扇区。则可用三个二进制位表示柱面,2个二进制位表示盘面,3个二进制位表示扇区。

若物理地址结构是(盘面号,柱面号,扇区号),且需要连续读取物理地址(00,000,000)~(00,001,111)的扇区:

(00,000,000)~(00,000,111)转两圈可读完。

之后再读取物理地址相邻的区域,即(00,001,000)~(00,001,111),需要启动磁头臂,将磁头移动到下一个磁道。

若物理地址结构是(柱面号,盘面号,扇区号),且需要连续读取物理地址(00,000,000)~(00,001,111)的扇区:

(00,000,000)~(00,000,111)由盘面0的磁头读入数据

之后再读取物理地址相邻的区域,即(00,001,000)~(00,001,111),由于柱面号/磁道号相同,只是盘面号不同,因此不需要移动磁头臂。只需要激活相邻盘面的磁头即可。

读取地址连续的磁盘块时,采用(柱面号,盘面号,扇区号)的地址结构可以减少磁头移动消耗的时间。

减少延迟时间的方法:错位命名

具体做法:让相邻盘面的扇区编号“错位”

原理:与“交替编号”的原理相同。“错位命名法可降低延迟时间”

磁盘的管理

磁盘初始化

引导块

计算机开始时需要进行一系列初始化的工作,这些初始化工作是通过执行初始化程序(自举程序)完成的。

坏块的管理

坏了、无法正常使用的就是“坏块”。这属于硬件故障,操作系统是无法修复的。应该将坏块标记出来,以免错误地使用到它。

对于简单的磁盘,可以在逻辑格式化时(建立文件系统时)对整个磁盘进行坏块检查,标明哪些扇区是坏扇区,比如:在FAT表上标明。(在这种方式中,坏块对操作系统不透明)

对于复杂的磁盘,磁盘控制器(磁盘设备内部的一个硬件部位)会维护一个坏块链表。

会保留一些“备用扇区”,用于替换坏块。这种方案称扇区备用。且这种处理方式中,坏块对操作系统透明。

第五章

I/O设备的概念和分类

什么是I/O设备?

“I/O”就是“输入/输出”(Input/Output)I/O设备就是可以将数据输入到计算机,或者可以接收计算机输出数据的外部设备,属于计算机中的硬件部件。

I/O设备的分类

按使用特性分类

按传输速率分类

按信息交换单位分类

I/O控制器

I/O设备的机械部件

I/O设备的机械部件主要用来执行具体I/O操作。如我们看得见摸得着的鼠标/键盘的按钮;显示器的LED屏;移动硬盘的磁臂、磁盘盘面。

I/O设备的电子部件通常是一块插入主板扩充槽的印刷电路板。

I/O设备的电子部件

CPU无法直接控制I/O设备的机械部件,因此I/O设备还要有一个电子部件作为CPU和I/O设备机械部件之间的“中介”,用于实现CPU对设备的控制。这个电子部件就是I/O控制器,又称设备控制器。CPU可控制I/O控制器,又由I/O控制器来控制设备的机械部件。

I/O控制器的组成

值得注意的小细节:
①一个I/O控制器可能会对应多个设备;
②数据寄存器、控制寄存器、状态寄存器可能有多个(如:每个控制/状态寄存器对应一个具体的设备),且这些寄存器都要有相应的地址,才能方便CPU操作。有的计算机会让这些寄存器占用内存地址的一部分,称为内存映像I/O;另一些计算机则采用I/O专用地址,即寄存器独立编址

I/O控制器的两种寄存器编址方式

I/O控制方式

程序直接控制方式

中断驱动方式

引入中断机制。由于I/O设备速度很慢,因此在CPU发出读/写命令后,可将等待I/O的进程阻塞,先切换到别的进程执行。当I/O完成后,控制器会向CPU发出一个中断信号,CPU检测到中断信号后,会保存当前进程的运行环境信息,转去执行中断处理程序处理该中断。处理中断的过程中,CPU从I/O控制器读一个字的数据传送到CPU寄存器,再写入主存。接着,CPU恢复等待I/0的进程(或其他进程)的运行环境,然后继续执行。

注意:
①CPU会在每个指令周期的末尾检查中断
②中断处理过程中需要保存、恢复进程的运行环境,这个过程是需要一定时间开销的。可见,如果中断发生的频率太高,也会降低系统性能。

DMA方式

与“中断驱动方式”相比,DMA方式(Direct Memory Access,直接存储器存取。主要用于块设备的I/O控制)有这样几个改进:
①数据的传送单位是“块”。不再是一个字、一个字的传送;
②数据的流向是从设备直接放入内存,或者从内存直接到设备。不再需要CPU作为“快递小哥”
③仅在传送一个或多个数据块的开始和结束时,才需要CPU干预。

通道控制方式

I/O软件的层次结构

用户层软件

设备独立性软件

设备独立性软件,又称设备无关性软件。与设备的硬件特性无关的功能几乎都在这一层实现。

主要实现的功能:
①向上层提供统一的调用接口(如 read/write 系统调用)
②设备的保护。原理类似与文件保护。设备被看做是一种特殊的文件,不同用户对各个文件的访问权限是不一样的,同理,对设备的访问权限也不一样。
③差错处理。设备独立性软件需要对一些设备的错误进行处理。
④设备的分配与回收
⑤数据缓冲区管理。可以通过缓冲技术屏蔽设备之间数据交换单位大小和传输速度的差异。
⑥建立逻辑设备名到物理设备名的映射关系;根据设备类型选择调用相应的驱动程序
用户或用户层软件发出I/O操作相关系统调用的系统调用时,需要指明此次要操作的I/O设备的逻辑设备名(eg:去学校打印店打印时,需要选择 打印机1/打印机2/打印机3,其实这些都是逻辑设备名)
设备独立性软件需要通过“逻辑设备表(LUT,Logical UnitTable)”来确定逻辑设备对应的物理设备,并找到该设备对应的设备驱动程序

操作系统系统可以采用两种方式管理逻辑设备表(LUT):
第一种方式,整个系统只设置一张LUT,这就意味着所有用户不能使用相同的逻辑设备名,因此这种方式只适用于单用户操作系统。
第二种方式,为每个用户设置一张LUT,各个用户使用的逻辑设备名可以重复,适用于多用户操作系统。系统会在用户登录时为其建立一个用户管理进程,而LUT就存放在用户管理进程的PCB,

设备驱动程序

中断处理程序

I/O核心子系统

I/O调度

设备保护

假脱机技术

什么是脱机技术?

假脱机技术

输入井和输出井

“假脱机技术”,又称“SPOOLing技术”是用软件的方式模拟脱机技术。SPOOLing 系统的组成如下:

输入进程与输出进程

要实现SPOOLing 技术,必须要有多道程序技术的支持。系统会建立“输入进程”和“输出进程”。

输入输出缓冲区

共享打印机原理分析

独占式设备——只允许各个进程串行使用的设备。一段时间内只能满足一个进程的请求。
共享设备——允许多个进程“同时”使用的设备(宏观上同时使用,微观上可能是交替使用)。可以同时满足多个进程的使用请求。

虽然系统中只有一个台打印机,但每个进程提出打印请求时,系统都会为在输出井中为其分配一个存储区(相当于分配了一个逻辑设备),使每个用户进程都觉得自己在独占一台打印机,从而实现对打印机的共享。SPOOLing 技术可以把一台物理设备虚拟成逻辑上的多台设备,可将独占式设备改造成共享设备。

设备的分配与回收

设备分配时应该考虑的因素

设备的固有属性可分为三种:独占设备、共享设备、虚拟设备。

独占设备——一个时段只能分配给一个进程(如打印机)。
共享设备——可同时分配给多个进程使用(如磁盘),各进程往往是宏观上同时共享使用设备而微观上交替使用。
虚拟设备——采用 SPOOLing 技术将独占设备改造成虚拟的共享设备,可同时分配给多个进程使用(如采用 SPOOLing 技术实现的共享打印机)。

设备的分配算法:

  • 先来先服务
  • 优先级高者优先
  • 短任务优先
  • ......

从进程运行的安全性上考虑,设备分配有两种方式:

  • 安全分配方式:为进程分配一个设备后就将进程阻塞,本次I/O完成后才将进程唤醒。(eg:考虑进程请求打印机打印输出的例子)
    一个时段内每个进程只能使用一个设备。
    优点:破坏了“请求和保持”条件,不会死锁。
    缺点:对于一个进程来说,CPU和I/0设备只能串行工作
  • 不安全分配方式:进程发出I/O请求后,系统为其分配I/O设备,进程可继续执行,之后还可以发出新的I/O请求。只有某个I/O请求得不到满足时才将进程阻塞。
    一个进程可以同时使用多个设备
    优点:进程的计算任务和I/O任务可以并行处理,使进程迅速推进。
    缺点:有可能发生死锁(死锁避免、死锁的检测和解除)

静态分配与动态分配

静态分配:进程运行前为其分配全部所需资源,运行结束后归还资源。破坏了“请求和保持”条件,不会发生死锁。
动态分配:进程运行过程中动态申请设备资源。

设备分配管理中的数据结构

“设备、控制器、通道”之间的关系:

一个通道可控制多个设备控制器,每个设备控制器可控制多个设备。

设备控制表—DCT

设备控制表(DCT):系统为每个设备配置一张DCT,用于记录设备情况。

控制器控制表—COCT

控制器控制表(COCT):每个设备控制器都会对应一张COCT。操作系统根据COCT的信息对控制器进行操作和管理。

通道控制表—CHCT

通道控制表(CHCT):每个通道都会对应一张CHCT。操作系统根据CHCT的信息对通道进行操作和管理。

系统设备表—SDT

系统设备表(SDT):记录了系统中全部设备的情况,每个设备对应一个表目。

设备分配的步骤

① 根据进程请求的物理设备名查找SDT(注:物理设备名是进程请求分配设备时提供的参数)
② 根据SDT找到DCT,若设备忙碌则将进程PCB挂到设备等待队列中,不忙碌则将设备分配给进程。
③ 根据DCT找到COCT,若控制器忙碌则将进程PCB挂到控制器等待队列中,不忙碌则将控制器分配给进程。
④ 根据COCT找到CHCT,若通道忙碌则将进程PCB挂到通道等待队列中,不忙碌则将通道分配给进程。

注:只有设备、控制器、通道三者都分配成功时,这次设备分配才算成功,之后便可启动IO设备进行数据传送。

设备分配的改进步骤

缺点:
① 用户编程时必须使用“物理设备名”,底层细节对用户不透明,不方便编程
② 若换了一个物理设备,则程序无法运行
③ 若进程请求的物理设备正在忙碌,则即使系统中还有同类型的设备,进程也必须阻塞等待

改进方法:建立逻辑设备名与物理设备名的映射机制,用户编程时只需提供逻辑设备名

① 根据进程请求的逻辑设备名査找SDT(注:用户编程时提供的逻辑设备名其实就是“设备类型”
② 查找SDT,找到用户进程指定类型的、并且空闲的设备,将其分配给该进程。操作系统在逻辑设备表(LUT)中新增一个表项。
③ 根据DCT找到COCT,若控制器忙碌则将进程PCB挂到控制器等待队列中,不忙碌则将控制器分配给进程。
④ 根据COCT找到CHCT,若通道忙碌则将进程PCB挂到通道等待队列中,不忙碌则将通道分配给进程。

逻辑设备表(LUT)建立了逻辑设备名与物理设备名之间的映射关系。
某用户进程第一次使用设备时使用逻辑设备名向操作系统发出请求,操作系统根据用户进程指定的设备类型(逻辑设备名)查找系统设备表,找到一个空闲设备分配给进程,并在LUT中增加相应表项。
如果之后用户进程再次通过相同的逻辑设备名请求使用设备则操作系统通过LUT表即可知道用户进程实际要使用的是哪个物理设备了,并且也能知道该设备的驱动程序入口地址。

逻辑设备表的设置问题:
整个系统只有一张LUT:各用户所用的逻辑设备名不允许重复,适用于单用户操作系统。
每个用户一张LUT:不同用户的逻辑设备名可重复,适用于多用户操作系统。

缓冲区管理

什么是缓冲区?有什么作用?

缓冲区是一个存储区域,可以由专门的硬件寄存器组成,也可利用内存作为缓冲区。使用硬件作为缓冲区的成本较高,容量也较小,一般仅用在对速度要求非常高的场合(如存储器管理中所用的联想寄存器,由于对页表的访问频率极高,因此使用速度很快的联想寄存器来存放页表项的副本)一般情况下,更多的是利用内存作为缓冲区,“设备独立性软件”的缓冲区管理就是要组织管理好这些缓冲区。

单缓冲

假设某用户进程请求某种块设备读入若干块的数据。若采用单缓冲的策略,操作系统会在主存中为其分配一个缓冲区(若题目中没有特别说明,一个缓冲区的大小就是一个块)
注意:当缓冲区数据非空时,不能往缓冲区冲入数据,只能从缓冲区把数据传出:当缓冲区为空时可以往缓冲区冲入数据,但必须把缓冲区充满以后,才能从缓冲区把数据传出。

用户进程的内存空间中,会分出一片工作区来接受输入/输出数据(一般也默认工作区大小与缓冲区相同)。

双缓冲

假设某用户进程请求某种块设备读入若干块的数据。若采用双缓冲的策略,操作系统会在主存中为其分配两个缓冲区。

单缓冲和双缓冲通信时的区别

两台机器之间通信时,可以配置缓冲区用于数据的发送和接受。

显然,若两个相互通信的机器只设置单缓冲区,在任一时刻只能实现数据的单向传输。

若两个相互通信的机器设置双缓冲区,则同一时刻可以实现双向的数据传输。
注:管道通信中的“管道”其实就是缓冲区。要实现数据的双向传输,必须设置两个管道。

循环缓冲区

将多个大小相等的缓冲区链接成一个循环队列。
注:以下图示中,橙色表示已充满数据的缓冲区,绿色表示空缓冲区

缓冲池

缓冲池由系统中共用的缓冲区组成。这些缓冲区按使用状况可以分为:空缓冲队列、装满输入数据的缓冲队列(输入队列)、装满输出数据的缓冲队列(输出队列)。另外,根据一个缓冲区在实际运算中扮演的功能不同,又设置了四种工作缓冲区:用于收容输入数据的工作缓冲区(hin)、用于提取输入数据的工作缓冲区(sin)、用于收容输出数据的工作缓冲区(hout)、用于提取输出数据的工作缓冲区(sout)

posted @ 2024-07-16 16:58  AirCL  阅读(9)  评论(0编辑  收藏  举报