操作系统(OS)

1.1.1操作系统的概念(定义)

操作系统(Operation System,OS)是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源的分配;(操作系统是系统资源的管理者)以提供给用户和其他软件方便的接口和环境(向上层提供方便易用的服务);他是计算机系统中最基本的系统组件。(是最接近硬件的一层软件)
直观地例子:打开windows操作系统的任务管理器

在这里插入图片描述

操作系统的功能和目标——作为系统资源的管理者

作为系统资源的管理者

  1. 提供的功能
    1. 处理机管理
    2. 存储器管理
    3. 文件管理
    4. 设备管理
  2. 目标:安全,高效

操作系统的功能和目标——向上层提供方便易用的服务

对于裸机(纯硬件)只听得懂二进制指令,如:0100110101010000111,硬件对外暴露了丑陋不友好的接口
在硬件之外安装了操作系统,操作系统对外暴露了美丽友好的接口
这其实是一种封装的思想:操作系统把一些丑陋的硬件功能封装成简单易用的服务,使用户能更方便地使用计算机,用户无需关心底层硬件的原理,只需要对操作系统发出命令即可。

  1. GUI:图形化用户接口(Graphical User Interface)
    用户可以使用形象的图形界面进行操作,而不需要记忆复杂的命令,参数、
  2. 交互式命令接口(特点:用户说一句,系统跟着做一句),如windows的cmd
  3. 批处理命令接口=脱机命令接口(特点:用户说一堆,系统跟着做一堆)
  4. 程序接口:可以在程序中进行系统调用来使用程序接口,普通用户不能直接使用程序接口,只能通过程序代码间接使用

操作系统的功能和目标——作为最接近硬件的层次

需要实现对硬件的拓展
没有任何软件支持的计算机称为裸机。在裸机上安装的操作系统,可以提供资源管理功能和方便用户的服务功能,将裸机改造成功能更强,使用更方便的机器
通常把覆盖了软件的机器称为扩充机器,又称之为虚拟机
操作系统对硬件机器的扩展:将CPU,内存,磁盘,显示器,键盘等硬件合理地组织起来,让各种硬件能够相互协调配合,实现更多更复杂的功能

总结

在这里插入图片描述

1.1.2操作系统的四个特征

并发

并发:指两个或多个时间在同一时间间隔内发生。这些事件在宏观是同时发生的,但微观上是交替发生的。常考易混概念——并行:指两个或多个事件在同一时刻同时发生。
操作系统的并发性指计算机系统中“同时”运行着多个程序,这些程序宏观上是同时运行着的,而微观上是交替运行的。
操作系统就是伴随着“多道程序技术”而出现的。因此,操作系统和程序并发是一起诞生的。
注意(重要考点):

  1. 单核CPU同一时刻只能执行一个程序,各个程序只能并发的执行
  2. 多核CPU同一时刻可以同时执行多个程序,多个程序可以并行的执行

共享

共享即资源共享,是指系统中的资源可供内存中多个并发执行的进程共同使用
两种资源共享方式:

  1. 互斥共享方式:系统中的某些资源,虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源
  2. 同时共享方式:系统中的某些资源,允许一个时间段内由多个进程“同时”对他们进行访问
    所谓的同时往往是宏观上的,而在微观上,这些进程可能是交替的对该资源进行访问的(即分时共享)

并发和共享的关系

并发性指计算机系统中同时存在着多个运行着的程序
共享性是指系统中的资源可供内存中多个并发执行的进程共同使用

虚拟

虚拟是指把一个物理上的实体变为若干个逻辑上的对应物。物理实体(前者)是实际存在的,而逻辑上对应物(后者)是用户感受到的
用一个例子来理解:
背景知识:一个程序需要被放入内存并给他分配CPU才能执行
我的电脑有4GB内存,但是我打开的软件需要的内存远远大于4GB,为什么他们还可以在我的电脑上同时运行呢?
答案:这是虚拟存储技术,实际只有4GB的内存,但在用户看来远远大于4GB,使用了虚拟技术中的空分复用技术

另一个例子:
我是一个单核CPU的电脑,但是却能同时开很多软件运行
问题:既然一个程序需要被分配CPU才能正常执行,那么为什么单核CPU的电脑中能同时运行那么多程序呢
答:这是虚拟处理器技术,实际上只有一个单核CPU,在用户看来有6个CPU在同时为自己服务
虚拟技术中的“时分复用技术”。微观上处理机在各个微小的时间段内交替运行着为各个进程服务

显然,如果失去了并发性,则一个时间段内系统只需要运行一道程序,那么就失去了实现虚拟性的意义了。因此,没有并发性,就谈不上虚拟性

异步

异步是指,在多道程序环境下,允许多个程序并发执行,但由于资源有限,进程的执行不是一贯到底的,而是走走停停,以不可预知的速度向前推进,这就是进程的异步性

如果失去了并发性,即系统只能串行的运行各个程序,那么每个程序的执行会一贯到底。只有系统拥有并发性,才有可能导致异步性

总结

在这里插入图片描述

1.2操作系统的发展与分类

手工操作阶段

在这里插入图片描述

批处理阶段——单道批处理系统

引入脱机输入/输出技术(用外围机+磁带完成),并由监督程序(操作系统的雏形)负责控制作业的输入,输出
在这里插入图片描述
在这里插入图片描述
主要优点:缓解了一定程度的人机速度矛盾,资源利用率有所提升
主要缺点:内存中仅能有一道程序运行,只有该程序运行结束之后才能调入下一道程序。CPU有大量时间是在空闲等待I/O完成。资源利用率依然很低

批处理阶段——多道批处理系统

在这里插入图片描述
主要优点:多道程序并发执行,共享计算机资源,资源利用率大幅度提升,CPU和其他资源更能保持忙碌状态,系统吞吐量增大
主要缺点:用户响应时间长,没有人机交互功能(用户提交自己的作业之后就只能等待计算机处理完成,中间不能控制自己的作业执行。eg:无法调试程序/无法在程序运行过程中输入一些参数)

分时操作系统

在这里插入图片描述
分时操作系统:计算机以时间片为单位轮流为各个用户/作业服务,各个用户可通过终端与计算机进行交互。
主要优点:用户请求可以被即时响应,解决了人机交互问题。允许多个用户同时使用一台计算机,并且用户对计算机的操作相互独立,感受不到别人的存在。
主要缺点:不能优先处理一些紧急任务。操作系统对各个用户/作业都是完全公平的,循环的为每个用户/作业服务一个时间片,不区分任务的紧急性

实时操作系统

主要优点:能够优先响应一些紧急任务,某些紧急任务不需要时间片排队
在实时操作系统的控制下,计算机系统接收到外部信号后及时进行处理,并且要在严格的时限内处理完事件。实时操作系统的主要特点是及时性和可靠性。
实时操作系统:

  1. 硬实时系统:必须在绝对严格的固定时间内完成处理
  2. 软实时系统:能接受偶尔违反时间规定

总结

在这里插入图片描述

1.3.1操作系统的运行机制

内核程序VS应用程序

我们普通程序员写的就是应用程序
微软苹果有一帮人负责实现操作系统,他们写的是内核程序
由很多内核程序组成了“操作系统内核”,或简称内核(Kernel),内核是操作系统最重要最核心的部分,也是最接近硬件的部分,甚至可以说一个操作系统只要有内核就可以了。操作系统的功能未必都在内核中,如图形化用户界面GUI

特权指令VS非特权指令

操作系统内核作为管理者,有时会让CPU执行一些特权指令,如:内存清零指令,这些指令影响重大,只允许“管理者”——即操作系统内核来使用
应用程序只能使用非特权指令,如:加法指令,减法指令等
在CPU设计和生产的时候就划分了特权指令和非特权指令,因此CPU执行一条指令前就能判断出其类型

内核态VS用户态

CPU有两种状态,内核态和用户态
处于内核态时,说明此时正在运行的是内核程序,此时可以执行特权指令
处于用户态时,说明此时正在运行的是应用程序,此时只能执行非特权指令
扩展:CPU中有一个寄存器叫程序状态寄存器(PSW),其中有个二进制位,1表示内核态,0表示用户态
别名:内核态=核心态=管态;用户态=目态

内核态用户态的切换

  1. 刚开机时,CPU为内核态,操作系统内核程序先上CPU运行
  2. 开机完成后,用户可以启动某个应用程序
  3. 操作系统内核程序在合适的时候主动让出CPU,让该应用程序上CPU运行(操作系统内核在让出CPU之前,会用一条特权指令把PSW的标志位设置为用户态)
  4. 应用程序运行在用户态
  5. 此时一位黑客在应用程序中植入了一条特权指令,企图破坏系统
  6. CPU发现接下来要执行的这条指令是特权指令,但是自己又处于用户态
  7. 这个非法事件会引发一个中断信号(CPU检测到中断信号后,会立即变为核心态,并停止运行当前的应用程序,转而运行处理中断信号的内核程序)
  8. 中断使操作系统再次夺回对CPU的控制权
  9. 操作系统会对引发中断的事件进行处理,处理完了再把CPU的使用权交给别的应用程序

总结

在这里插入图片描述

1.3.2中断和异常

中断的作用

CPU上会运行两种程序,一种是操作系统内核程序(整个系统的管理者),一种是应用程序
在合适的情况下,操作系统内核会把CPU的使用权主动让给应用程序,“中断”是让操作系统内核夺回CPU使用权的唯一途径。中断会使CPU由用户态变为内核态,使操作系统重新夺回对CPU的使用权
如果没有“中断”机制,那么一旦应用程序上CPU运行,CPU就会一直运行这个应用程序
内核态—>用户态:执行一条特权指令——修改PSW的标志位为“用户态”,这个动作意味着操作系统将主动让出CPU使用权
用户态—>内核态:由中断引发,硬件自动完成变态过程,触发中断信号意味着操作系统将强行夺回CPU的使用权

中断的类型

  1. 内中断(也称异常,例外):与当前执行的指令有关,中断信号来源于CPU内部
    例:除了上面提到的被黑客植入了不安全的指令以外,有时候应用程序向请求操作系统内核的服务,此时会执行一条特殊的指令——陷入指令(执行陷入指令,意味着应用程序主动地将CPU控制权还给操作系统内核。系统调用就是通过陷入指令完成的),该指令会引发一个内部中断信号
  2. 外中断(也称中断):与当前执行的指令无关,中断信号来源于CPU外部
    例:时钟中断——由时钟部件发来的中断信号(没过50ms发送一个中断信号,来分配cpu的执行权)

大多数的教材试卷中,终端特指外中断。而内中断一般成为异常

异常

  1. 陷阱,陷入(trap):由陷入指令引发的,是应用程序故意引发的
  2. 故障(fault):由错误条件引起的,可能被内核程序修复。内核程序修复故障后会把CPU使用权还给应用程序,让他继续执行下去。如:缺页故障
  3. 终止(Abort):由致命错误引起,内核程序无法修复该错误,因此一般不再将CPU使用权还给引发终止的应用程序,而是直接终止该应用层序。如:整数除0,非法使用特权指令

中断机制的基本原理

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

总结

在这里插入图片描述

1.3.3系统调用

什么是系统调用

操作系统作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要包括命令接口和程序接口。其中,程序接口由一组系统调用组成。
在这里插入图片描述
系统调用是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过系统调用来请求获得操作系统内核的服务

系统调用与库函数的区别

在这里插入图片描述

普通应用程序可直接进行系统调用,也可以使用库函数。有的库函数设计系统调用,有的不涉及 ↑ \uparrow
编程语言向上提供库函数。有时会将系统调用封装成库函数,以隐藏系统调用的一些细节,使程序员编程更加方便 ↑ \uparrow
操作系统向上提供系统调用,使得上层程序能请求内核的服务 ↑ \uparrow
逻辑 ↑ \uparrow

为什么系统调用是必须的

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

系统调用的过程

  1. 应用程序使用传参指令给CPU的寄存器传递一个参数,指明系统调用类型,如fork,可以有多个参数
  2. 然后执行陷入指令,会引发一个内中断信号,该中断由陷入指令引发,因此转入响应的中断处理程序——即系统调用的入口程序
  3. 此时系统调用入口程序会根据寄存器中的参数判断用户需要哪种系统调用服务,然后执行响应系统调用服务的指令
  4. 然后CPU转换为用户态接着执行相应的指令
    总结一下大概为:
    传递系统调用参数—>执行陷入指令(用户态)—>执行相应的内请求核程序处理系统调用(和心态)—>返回应用程序
    注意:陷入指令是在用户态执行的,执行陷入指令之后立即引发一个内中断,使CPU进入核心态。并且发出系统调用请求是在用户态,而对系统调用的相应处理在核心态下进行
    注意别名:陷入指令=trap指令=访管指令

总结

在这里插入图片描述

1.4.1操作系统体系结构(上)

内核是操作系统最基本最核心的部分
实现操作系统内核功能的那些程序就是内核程序

操作系统的体系结构

在这里插入图片描述

一个故事:现在,应用程序想要请求操作系统的服务,这个服务的处理同时涉及到进程管理,存储管理,设备管理
在这里插入图片描述
注意:变态的过程是有成本的,要消耗不少时间,频繁的变态会降低系统性能

总结

在这里插入图片描述

1.4.2操作系统体系结构(下)

操作系统结构——分层结构

在这里插入图片描述
最底层是硬件,最高层是用户接口,每层可调用更低一层

操作系统结构——模块化

模块化是将操作系统按功能划分为若干个具有一定独立性的模块。每个模块具有某方面的管理功能,并规定好各个模块之间的接口,使各模块之间能通过接口进行通信。还可以进一步将各个模块细分为若干个具有一定功能的子模块,同样也规定好各模块之间的接口。把这个设计方案称为模块—接口法,如图所示
在这里插入图片描述

操作系统结构

分类特性,思想优点缺点
分层结构内核分多层,每层可单向调用更低一层提供的接口1.便于调试和验证,自底向上逐层调试验证2.易扩充和易维护,各层之间调用接口清晰固定仅可调用相邻底层,难以合理定义各层的边界2.效率低,不可跨层调用,系统调用执行时间长
模块化将内核划分为多个模块,各模块之间相互协作。内核=主模块+可加载内核模块主,主模块:只负责核心功能,如进程调度,内存管理。 可加载内核模块:可以动态加载新模块到内核,而无需重新编译整个内核1.模块间逻辑清晰易于维护,确定模块间接口后即可多模块同时开发2.支持动态加载新的内核模块(如:安装设备驱动程序,安装新的文件系统模块到内核),增强OS适应性3.任何模块都可以直接调用其他模块。无需采用消息传递进行通信,效率高模块间的接口定义未必合理,实用2.模块间相互依赖,更难调试和验证
宏内核(大内核)所有的系统功能都放在内核里(大内核的OS通常也采用了模块化的设计思想)性能高,内核内部各种功能都可以直接相互调用内核庞大功能复杂,难以维护2.大内核中某个功能模块出错,就可能导致整个系统崩溃
微内核只把中断,原语,进程通信等最核心的功能放入内核。进程管理,文件管理,设备管理等功能以用户进程的形式运行在用户态1.内核小功能少,易于维护,内核可靠性高2.内核外的某个功能模块出错不会导致整个系统崩溃性能低,需要频繁的切换用户态/和心态,用户态下的各功能模块不可以直接相互调用,只能通过内核的消息传递来间接通信2.用户态下的各功能模块不可以直接相互调用,只能通过内核的消息传递来间接通信
外核(exokernel)内核负责进程调度,进程通信等功能,外核负责为用户进程分配未经抽象的硬件资源,且由外核负责保证资源使用安全1.外核可直接给用户进程分配不虚拟不抽象的硬件资源,使用户进程可以更灵活的使用硬件资源2.减少了虚拟硬件资源的映射层,提高效率1.降低了系统一致性2.使系统变得更复杂

1.5操作系统引导

安全操作系统后

在这里插入图片描述
C盘(是这个磁盘的活动分区,安装了操作系统),将C盘内部进一步细分
在这里插入图片描述

操作系统引导(开机过程)

在这里插入图片描述

  1. CPU从一个特定主存地址开始取指令,执行ROM中的引导程序(先进行硬件自检,再开机)
  2. 将磁盘的第一块——主引导记录读入内存,执行磁盘引导程序,扫描分区表
  3. 从活动分区(又称主分区,即安装了操作系统的分区)读入分区引导记录,执行其中的程序
  4. 从根目录下找到完成的操作系统初始化程序(即启动管理器)并执行,完成开机的一系列操作

1.6虚拟机

虚拟机:使用虚拟化技术,将一台物理机虚拟化为多台虚拟机器(Virtual Machine,VM),每个虚拟机器都可以独立运行一个操作系统
同义术语:虚拟机管理系统/虚拟机监控程序/Virtual Machine Monitor/Hypervisor
在这里插入图片描述
在这里插入图片描述

两类虚拟机管理程序(VMM)的对比

方面第一类VMM第二类VMM
对物理资源的控制权直接运行在硬件之上,能直接控制和分配物理资源运行在Host OS之上,依赖于Host OS为其分配物理资源
资源分配方式在安装Guest OS时,VMM要在原本的硬件上自行分配存储空间,类似于外核的分配方式,分配未经抽象的物理硬件Guest OS拥有自己的虚拟硬盘,该盘实际上是Host OS文件系统中的一个大文件、Guest OS分配到的内存是虚拟内存
性能性能更好性能更差,虚拟HostOS作为中介
可支持的虚拟机数量更多,不需要与HostOS竞争资源,相同硬件资源可以支持更多的虚拟机更少,HostOS本身需要使用物理资源, HostOS上运行的其他进程也需要物理资源
虚拟机的可迁移性更差更好,只需导出虚拟机镜像文件即可迁移到另一台HostOS上,商业化应用更广泛
运行模式第一类VMM运行在 最高特权级(Ring 0),可以执行最高特权的指令第二类VMM部分运行在用户态,部分运行在内核态。GuestOS发出的系统调用会被VMM截获,并转化为VMM对HostOS的调用

2.1.1进程的概念,组成,特征

进程的概念

程序:是静态的,就是个存放在磁盘里的可执行文件,就是一系列指令的集合。
进程(Process):是动态的,是程序的一次执行过程(同一个程序的多次执行会对应多个进程)

进程的组成——PCB

当进程被创建时, 操作系统会为该进程分配一个唯一的,不重复的身份证号——PID(Process ID,进程ID)
操作系统要记录PID,进程所属用户ID(UID)(基本的进程描述信息,可以让操作系统区分各个进程)
还要记录给进程分配了哪些资源(如:分配了多少内存,正在使用哪些I/O设备,正在使用哪些文件)(可用于实现操作系统对资源的管理)
还要记录进程的运行情况(如:CPU的使用时间,磁盘使用情况,网络流量使用情况等)(可用于实现操作系统对进程的控制,调度)
这些信息都被保存在一个数据结构PCB(Process Control Block)中,即进程控制块,操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放在PCB中

在这里插入图片描述

进程的组成——程序段,数据段

在这里插入图片描述
PCB是给操作系统用的
程序段数据段是给进程自己用的

程序是如何运行的

在这里插入图片描述

进程的组成

程序段,数据段,PCB三部分组成了进程实体(进程映像)
引入进程实体的概念后,可把进程定义:进程是进程实体的运行过程,是系统进行资源分配和调度(一个进程被调度,就是指操作系统决定让这个进程上CPU运行)的一个独立单位
PCB是进程存在的唯一标志

进程的特征

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

  1. 动态性:进程是程序的一次执行过程,是动态的产生,变化和消亡的(动态性是进程的最基本的特性)
  2. 并发性:内存中有多个进程实体,各个进程可以并发执行
  3. 独立性:进程是能独立运行,独立获得资源,独立接受调度的基本单位
  4. 异步性:各进程按各自独立的,不可预知的速度向前推进,操作系统要提供进程同步机制来解决异步问题(异步性会导致并发程序执行结果的不确定性)
  5. 结构性:每个进程都会配置一个PCB,结构上看,进程由程序段,数据段,PCB组成。

总结

在这里插入图片描述

2.1.2 进程的状态与转换,进程的组织

创建态,就绪态

进程正在被创建时,他的状态是创建态,在这个阶段操作系统会为进程分配资源,初始化PCB
当进程创建完成后,便进入就绪态,处于就绪态的进程已经具备运行条件,但由于没有空闲CPU,就暂时不能运行

运行态

系统中可能会有很多个进程都处于就绪态,当CPU空闲时,操作系统就会选择一个就绪进程,让他行处理机运行。如果一个进程此时在CPU上运行,那么这个进程处于运行态,CPU会执行该进程对应的程序(执行指令序列)

阻塞态

在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应)
在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让他进入阻塞态

终止态

一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入终止态,操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。当终止进程的工作完成后,这个进程就彻底消失了

进程状态的转换

在这里插入图片描述
在这里插入图片描述
进程PCB中,会有一个变量state来表示进程的当前状态。如:1表示创建态,2表示就绪态,3表示运行态。为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来

进程的组织——链接方式

在这里插入图片描述

进程的组织——索引方式

在这里插入图片描述

2.1.3进程控制

什么是进程控制

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

如何实现进程控制

在这里插入图片描述
如果不能一气呵成,就有可能导致操作系统中的某些关键数据结构信息不统一的情况,这会影响操作系统进行别的管理工作。

如何实现原语的原子性

原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断。可以用关中断指令和开中断指令这两个特权指令实现原子性
正常情况下:CPU每执行完一条指令都会例行检查是否有中断信号需要处理,如果有,则暂停运行当前这段程序,转而执行相应的中断处理程序。
但是如果执行了关中断指令,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查
在这里插入图片描述

进程控制相关的原语

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

程序是如何运行的

在这里插入图片描述
CPU中会设置很多寄存器,用来存放程序运行过程中所需的某些数据

  1. PWS:程序状态字寄存器
  2. PC:程序计数器,存放下一条指令的地址
  3. IR:指令寄存器,存放当前正在执行的指令
  4. 通用寄存器:其他一些必要信息
  5. 等等等

另一个进程在运行过程中也会使用各个寄存器,所以在进程切换时现在PCB中保存这个进程的运行环境(保存一些必要的寄存器信息),当原来的进程再次投入运行时,可以通过PCB恢复它的运行环境

总结

在这里插入图片描述

2.1.4进程通信

什么是进程间通信

进程间通信(Inter-Process Communication,IPC)是指两个进程之间产生数据交互。

为什么进程通信需要操作系统的支持

进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立,为了保证安全,一个进程不能直接访问另一个进程的地址空间

共享存储

在这里插入图片描述

  1. 基于存储区的共享:操作系统在内存中划出一块共享存储区,数据的形式,存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式
  2. 基于数据结构的共享:比如共享空间里只能放一个长度为10的数组,这种共享方式速度慢,限制多,是一种低级通信方式

为避免出错,各个进程对共享空间的访问时互斥的

消息传递

进程间的数据交换以格式化的消息(Message)为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换
在这里插入图片描述
消息头包括:
1. 发送进程ID
2. 接受进程ID
3. 消息长度等格式化的信息
消息传递又分为
1. 直接通信方式(消息发送进程指明接受进程的ID)
2. 间接通信方式(通过信箱间接的通信。因此又称为信箱通信方式)

直接通信方式

在这里插入图片描述

间接通信方式

在这里插入图片描述

管道通信

在这里插入图片描述
管道是一个特殊的共享文件,又名pipe文件,其实就是在内存中开辟一个大小固定的内存缓冲区(先进先出,queue)

  1. 管道只能采用半双工通信,某一时间段内只能实现单向的传输,如果要实现双向同时通信,则需要设置两个管道
  2. 各进程要互斥的访问管道(由操作系统实现)
  3. 当管道写满时,写进程将阻塞,直到读进程将管道中的数据取走,即可唤醒写进程
  4. 当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程
  5. 管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:
    1. 一个管道允许多个写进程,一个读进程
    2. 允许有多个写进程,多个读进程 ,但系统会让各个读进程轮流从管道中读取数据

总结

在这里插入图片描述

2.1.5线程的概念

什么是线程,为什么要引入线程

有的进程可能需要同时做很多事,而传统的进程只能串行的执行一系列程序,为此,引入了线程,来增加并发度
传统的进程是程序执行流的最小单位,引入线程后,线程就成为了程序执行流的最小单位
可以把线程理解为轻量级进程,线程是一个基本的CPU执行单元,也是程序 执行流的最小单位,引入线程之后,不仅是进程之间可以并发,进程内部的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如QQ视频,聊天,传文件)
引入线程后,进程只作为除CPU之外的系统资源的分配单元(如打印机,内存地址空间等都是分配给进程的)

引入线程机制后,有什么变化

在这里插入图片描述

线程的属性

在这里插入图片描述

2.1.6线程的实现方式和现成的模型

线程的实现方式

用户级线程

用户级线程(User-Level Thread,ULT)(历史背景:早期的操作系统(如:早期Unix)只支持进程,不支持线程,当时的线程是由线程库来实现的)
在这里插入图片描述
从代码的角度看,线程其实就是一段代码逻辑,上述三段代码逻辑可以看做三个线程,while循环就是一个最弱智的线程库,线程库完成了对线程的管理工作(如调度)
很多编程语言提供了强大的线程库,可以实现线程的创建,销毁,调度等功能

  1. 线程的管理工作由谁来完成:用户级线程由应用程序通过线程库来实现,所有的线程管理工作都由应用程序负责(包括线程切换)
  2. 线程切换是否需要CPU变态:用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预
  3. 操作系统是否能意识到用户级线程的存在:在用户看来是有多个线程,但是在操作系统内核看来,意识不到线程的存在
  4. 这种实现方式有什么优点和缺点
    1. 优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
    2. 缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并发运行

内核级线程

内核级线程(Kernel-Level Thread,KLT,又称内核支持的线程)(由操作系统支持的线程)
大多数现代操作系统都实现了内核级线程,如Windows,Linux

  1. 线程的管理工作由谁来完成:内核级线程的管理工作由操作系统内核完成
  2. 线程切换是否需要CPU变态:线程调度,切换等工作都由内核负责,因此内核级线程的切换必然需要在和心态下才能完成
  3. 操作系统是否能意识到用户级线程的存在:操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块),通过TCB对线程进行管理,“内核级线程”就是从擦偶子系统内核视角能看到的线程
  4. 这种实现方式有什么优点和缺点
    1. 优点:当一个线程被阻塞后,别的线程可以继续执行,并发能力强,多线程可在多核处理机上并发执行
    2. 缺点:一个用户进程会占用多个内核级线程,线程切换由操作系统内核来完成,需要切换到核心态,因此线程管理的成本高,代价大

多线程模型

一对一模型

在这里插入图片描述

一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程
优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强,多线程可在多核处理机上并发执行
缺点:一个用户进程会占用多个内核级线程,线程切换由操作系统内核来完成,因此线程管理的成本高,代价大

多对一模型

多个用户级线程映射到一个内核级线程,且一个进程只被分配一个内核级线程
优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
缺点:当一个用户线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并发运行
重点:操作系统只看得见内核级线程,因此只有内核级线程才是处理机分配的单位
在这里插入图片描述

多对多模型

n用户以及线程映射到m个内核级线程(n >= m)。每个用户进程对应m和内核级线程
克服了多对一模型并发度不高的缺点(一个阻塞全体阻塞),又客服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点

可以这么理解:
用户级线程是代码逻辑的载体
内核级线程是运行机会的载体(内核级线程才是处理机分配的单位)
一段代码逻辑只有获得了运行机会才会被CPU执行

总结

在这里插入图片描述

2.1.7线程的状态与转换

在这里插入图片描述

线程的组织与控制

在这里插入图片描述

2.2.1调度的概念,层次

调度的基本概念

当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序,这就是调度研究的问题

调度的三个层次

高级调度(作业调度)

作业:一个具体的任务
用户向系统提交一个作业=用户让操作系统启动一个程序(或者处理一个具体的任务)
高级调度(作业调度):按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB

低级调度(进程调度)

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

中级调度

中间调度(内存调度)——按照某种策略决定将哪个处于挂起状态的进程重新调入内存
内存不够时,可将某些进程的数据调出外存,等内存空闲或者进程需要运行时再重新调入内存。
一个进程可能会被多次调出调入,因此中级调度发生的频率要比高级调度更高

进程的挂起态和七状态模型

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

在这里插入图片描述
注意挂起和阻塞的区别,两种状态都是暂时不能获得CPU的服务,但挂起态是将进程映像调到外存去了,而阻塞态下进程映像还在内存中
有的操作系统会把就绪挂起和阻塞挂起分为两个挂起队列,甚至会根据阻塞原因不同再把阻塞挂起进一步细分为多个队列

三层调度的联系,对比

分类要做什么调度发生在发生频率对进程状态的影响
高级调度(作业调度)按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程外存->内存(面向作业)最低无->创建态->就绪态
中级调度(内存调度)按照某种规则,从挂起队列中选择合适的进程将其数据调回内存外存->内存(面向进程)中等挂起态->就绪态(阻塞挂起->阻塞态)
低级调度(进程调度)按照某种规则,从就绪队列中选择一个进程为其分配处理机内存->CPU最高就绪态->运行态

总结

在这里插入图片描述

2.2.2进程调度的时机,切换的过程,方式

进程调度的时机

进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机
什么时候需要进行进程调度和切换:

  1. 当前运行的进程主动放弃处理机
    1. 进程正常终止
    2. 运行过程中发生异常而终止
    3. 进程主动请求阻塞(如等待I/O)
  2. 当前运行的进程被动放弃处理机
    1. 分给进程的时间片用完
    2. 有更紧急的事需要处理(如I/O中断)
    3. 有更高优先级的进程进入就绪队列

不能进行进程调度和切换的情况:
1. 在处理中断的过程中。中断处理过程复杂,与硬件密切相关,很难做到在中断处理过程中进行进程切换
2. 进程在操作系统内核程序临界区中
3. 在原子操作过程中(原语)。原子操作不可中断,要一气呵成(如之前说的修改PCB中进程状态标志,并把PCB放到相应队列)

临界资源:一个时间段内只允许一个进程使用的资源,各进程需要互斥的访问临界资源
临界区:访问临界资源的那段代码
内核程序临界区一般是用来访问某种内核数据结构的,比如进程的就绪队列(由各就绪进程的PCB组成)

进程调度的方式

非剥夺调度方式

非剥夺调度方式,又称非抢占方式。即,只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态(实现简单,系统开销小但是无法及时处理紧急任务,适合于早期的批处理系统)

剥夺调度方式

剥夺调度方式,又称抢占方式。当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的进程(可以优先处理更紧急的进程,也可实现让各进程按时间片轮流执行的功能(通过时钟中断),适合于分时操作系统,实时操作系统)

进程的切换和过程

狭义的进程调度和进程切换的区别
狭义的进程调度指的是从就绪队列中选中一个要运行的进程(这个进程可以是刚刚被暂停执行的进程,也可以是另一个进程,后一种情况就需要进程切换)
进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程
广义的进程调度包含了选择一个进程和进程切换两个步骤

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

  1. 对原来运行的进程各种数据的保存
  2. 对新的进程各种数据的恢复(如程序计数器,程序状态字等等)

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

总结

在这里插入图片描述

2.2.3调度器,闲逛进程

调度器

在这里插入图片描述
2,3由调度程序引起,调度程序决定:

  1. 让谁运行——调度算法
  2. 运行多长时间——时间片大小
    调度时机——什么事件会触发调度程序
    1. 创建新进程
    2. 进程退出
    3. 运行进程阻塞
    4. I/O中断发生(可能唤醒某些阻塞线程)

非抢占式调度策略,只有运行进程阻塞或退出才触发调度程序工作
抢占式调度策略,每个时钟中断或k个时钟中断会触发调度程序工作

对于支持内核级线程的操作系统,调度程序的处理对象是内核线程

闲逛进程

调度程序永远的备胎,没有其他就绪进程时,运行闲逛进程(idle)
闲逛进程的特性:

  1. 优先级最低
  2. 可以是0地址指令,占一个完整的指令周期(指令周期末尾例行检查中断)
  3. 能耗低

调度算法的评价指标

CPU利用率

CPU利用率:指CPU“忙碌”的时间占总时间的比例

系统吞吐量

对于计算机来说,希望能用尽可能少的时间处理完尽可能多的作业
系统吞吐量:单位时间内完成作业的数量

周转时间

周转时间:指从作业被提交给系统开始,到作业完成位置的这段时间间隔
他包括四个部分:
1. 作业在外存后备队列上等待作业调度(高级调度)的时间
2. 进程在就绪队列上等待进程调度(低级调度)的时间
3. 进程在CPU上执行的时间
4. 进程等待I/O操作完成的时间
后三项在一个作业的整个处理过程中,可能发生多次
周转时间=作业完成时间-作业提交时间
带权周转时间=作业完成时间-作业提交时间/作业实际运行时间

等待时间

等待时间:指进程/作业处于等待处理机状态之和,等待时间越长,用户满意度越低
对于进程来说,等待时间就是指进程建立后等待被服务的时间之和,在等待I/O完成的期间其实进程也是在被服务的,所以不计入等待时间
对于作业来说,不仅要考虑建立进程后的等待时间,还要加上作业在外存后备队列中等待的时间
一个作业总共需要被CPU服务多久,被I/O设备服务多久一般是确定不变的,因此调度算法其实只会影响作业/进程的等待时间。当然,与前面指标类似,也有平均等待时间来评价整体性能

响应时间

响应时间:指从用户提交请求到首次产生相应所用的时间

总结

在这里插入图片描述

调度算法

先来先服务(FCFS,First Come First Serve)

方面评价
算法思想主要从公平的角度考虑
算法规则按照作业/进程到达的先后顺序进行服务
用户作业/进程调度用于作业调度时,考虑的是哪个作业先到达后备队列;用于进程调度时考虑的是哪个进场先到达就绪队列
是否可抢占非抢占式的算法
优点公平,算法实现简单
缺点排在长作业后面的短作业需要等待很长时间,带权周转时间很长,对短作业来说用户体验不好。即FCFS算法对长作业有利,对短作业不利
是否会导致饥饿不会

短作业优先(SJF,Shortest Job First)

方面评价
算法思想追求最少得平均等待时间,最少的平均周转时间,最少的平均带权周转时间
算法规则最短的作业/进程优先得到服务(所谓最短,是指要求服务时间最短)
用于作业/进程调度即可用于作业调度,也可用与进程调度。用于进程调度时称为短进程优先(SPF,Shortest Process First)算法
是否可抢占SJF和SPF是非抢占式的算法。但是也有抢占式的版本——最短剩余时间优先算法(SRTN,Shortest Reamaining Time Next)
优点最短的平均等待时间和平均周转时间
缺点不公平,对短作业有利,长作业不利。可能产生饥饿现象。另外,作业/线程是由用户提供的,并不一定真实,不一定能做到真正的短作业优先
是否会导致饥饿会。如果源源不断的有短作业/进程到来。可能使长作业/进程长时间得不到服务,产生饥饿现象,如果一直得不到服务,则称为饿死

注意:

  1. 如果题目中未特别说明,所提到的短作业/进程优先算法默认是非抢占式的
  2. SJF调度算法的平均等待时间,平均周转时间最少,但这是错误的,不严谨的。最短剩余时间优先算法得到的平均等待时间,平均周转时间更少。应该加上一个条件,在所有进程同时可运行时,采用SJF调度算法的平均等待时间,平均周转时间最少。或者说,在所有进程都几乎同时到达时,采用SJF调度算法的平均等待时间,平均周转时间最少。如果不加以上这些条件,则应该说抢占式的短作业/进程优先调度算法(最短剩余时间优先,SRNT算法)的平局等待时间,平均周转时间最少
  3. 虽然严格来说, SJF的平均等待时间,平均周转时间不一定最少,但相比于其他算法(如FCFS),SJF依然可以获得较少的平均等待时间,平均周转时间

高响应比优先(HRRN,Highesr Response Ratio Next)

方面评价
算法思想要综合考虑作业/进程的等待时间和要求服务的时间
算法规则在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务
用于作业/进程调度既可以用于作业调度,也可以用于进程调度
是否可抢占非抢占式的算法。因此只有当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算响应比
评价等待时间相同的同时,要求服务时间短的优先,要求服务时间相同时,等待时间长的优先。对于长作业来说,随着等待时间越来越久,其响应比也会越来也要打,从而避免了长作业饥饿的问题

总结

在这里插入图片描述

2.2.6调度算法(2)

时间片轮转调度算法(RR,Round-Robin)

方面评价
算法思想公平得,轮流的为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
算法规则按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片(如100ms)。若进程未在一个时间片执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队
用于作业/进程调度用于进程调度(只有作业放入内存建立了响应的进程后,才能被分配处理机时间片)
是否可抢占若进程未在时间片内运行完,将被强行剥夺处理机使用权,因此时间片轮转调度算法属于抢占式的算法,由时钟装置发出时钟中断来通知CPU时间已到
优点公平,响应快,适用于分时操作系统
缺点由于高频率的进程切换,因此有一定开销,不区分任务的紧急程度
是否会导致饥饿不会

注意:

  1. 时间片太大,使得每个进程都可以在一个时间片内完成,则时间片轮询调度算法退化为先来先服务调度算法,并且会增大进程的响应时间,因此时间片不能太大
  2. 时间片太小:进程调度/切换是有时间代价的(保存/恢复运行环境),因此如果时间片太小,会导致线程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程的执行时间比例减少。可见时间片也不能太小

优先级调度算法

方面评价
算法思想随着计算机的发展,特别是实时操作系统的出现,越来雨多的应用场景需要根据任务的紧急程度来决定处理顺序
算法规则每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程
用于作业/进程调度既可用与作业调度,也可用于进程调度。甚至还会用于I/O调度
是否可抢占抢占式,非抢占式都有。他们的区别在于:非抢占式只需在进程主动放弃处理机时调度即可,而抢占式还需在就绪队列变化时,检查是否会发生抢占
优点用优先级区分紧急程度,重要程度。适用于实时操作系统,可灵活的调整对各种作业/进程的偏好程度
缺点若源于不断地有高优先级进程到来,则可能导致饥饿

如何合理的设置各类进程的优先级,通常:

  1. 系统进程优先级高于用户进程
  2. 前台进程高于后台进程
  3. 操作系统更偏好I/O型进程(相对的是计算型进程)

多级反馈队列调度算法

方面评价
算法思想对其他调度算法的这种权恒
算法规则1. 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大2.新进程到达时先进入第一级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾,如果此时已经是在最下级的队列,则重新放回该队列队尾3. 只有第k级队列为空时,才会为k+!级队头的进程分配时间片
用于作业/进程调度用于进程调度
是否可抢占抢占式的算法,在k级队列的进程运行过程中,若更上级的队列中进入了一个新进程,则由于新进程处于优先级更高的队列中,因此新进程会抢占处理机,原来运行的进程放回k队列队尾
优点拥有前面的各种优点

总结

在这里插入图片描述

2.2.调度算法(3)

多级队列调度算法

系统中按进程类型设置多个对队列,进程创建成功后插入某个队列
在这里插入图片描述
队列之间可采取固定优先级,或时间片划分:
1. 固定优先级:高优先级空时低优先级进程才能被调度
2. 时间片划分:如三个队列分配时间50%,40%,10%
各队列可采用不同的调度策略:如:
1. 系统进程队列采用优先级调度
2. 交互式队列采用RR
3. 批处理队列采用FCFS

2.3.1进程同步,进程互斥

什么是进程同步

知识点回顾:进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的,不可预知的速度向前推进
读进程和写进程并发地运行,由于并发必然导致异步性,因此写数据和读数据两个操作执行的先后顺序是不确定的。而实际应用中,又必须按照写数据->读数据的顺序来执行的。如何解决这种异步问题,就是进程同步所讨论的内容
同步也称为直接制约关系,他是为了完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调他们的工作次序而产生的制约关系。进程间的直接制约关系就是源于他们之间的相互合作。

什么是进程互斥

进程的并发需要共享支持。各个并发执行的进程不可避免的需要共享一些资源(比如内存,打印机,摄像头这样的I/O设备)
两种资源共享方式:
1. 互斥共享方式:系统中的某些资源,虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源
2. 同时共享方式:系统中的某些资源,允许一个时间段内由多个进程同时对他们进行访问

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

对临界资源的互斥访问,可以在逻辑上分为如下四个部分:
在这里插入图片描述
注意:
1. 临界区是进程中访问临界资源的代码段
2. 进入区和退出区是负责实现互斥的代码段
3. 临界区也可称为临界段

为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则:
1. 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区
2. 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待
3. 有限等待。对请求访问的线程,应保证能在有限时间内进入临界区(保证不会饥饿)
4. 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。

总结

在这里插入图片描述

2.3.2进程互斥的软件实现方法

单标志法

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

双标志先检查法

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

双标志后检查法

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

若按照1526的顺序执行,P0和P1将都无法进入临界区
因此,双标志后检查法虽然解决了忙则等待的问题,但是又违背了空闲让进和有限等待原则,会因各进程都长期无法访问临界资源而产生饥饿现象。

PeterSon算法

算法思想:结合双标志法,单标志法的思想。如果双方都争着想进入临界区,那可以让进程尝试谦让。
在这里插入图片描述
PeterSon算法用软件方法解决了进程互斥问题,遵循了空闲让进,忙则等待,有限等待三个原则,但是依然未遵循让权等待的原则
PeterSon算法相较于之前三种软件解决方案来说,是最好的,但依然不够好

总结

在这里插入图片描述

2.3.3进程互斥的硬件实现方法

中断屏蔽方法

利用开/关中断指令实现(与原语的实现思想相同,即在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切换,因此也不可能发生两个同时访问临界区的情况)
在这里插入图片描述
优点:简单,搞笑
缺点:不适用于多处理机:只适用于操作系统内核进程,不适用于用户进程(因为开/关中断指令只能运行在内核态,这组指令如果能让用户随机使用会很危险)

TestAndSet指令

简称TS指令,也有地方称为TestAndSetLock指令,或者TSL指令
TSL指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑
在这里插入图片描述

Swap指令

有的地方也叫Exchange指令,或简称XCHG指令。
Swap指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。以下是用C语言描述的逻辑
在这里插入图片描述

总结

在这里插入图片描述

2.3.4互斥锁

进程互斥——锁

解决临界区最简单的工具就是互斥锁(mutex lock)。一个进程在进入临界区时应获得锁;在退出临界区时释放锁。函数acquire()获得锁,而函数release()释放锁
每个互斥锁有一个布尔变量available,表示锁是否可用。如果锁是可用的,调用acqueire()会成功,且锁不再可用。当一个进程试图获取不可用的锁时,会被阻塞,直到锁被释放。
在这里插入图片描述
acquire()或release()的执行必须是原子操作,因此互斥锁通常采用硬件机制来实现。
互斥锁的主要缺点是忙等待,当有一个进程在临界区中,任何其他进程在进入临界区时必须连续循环调用acquire()。当多个进程共享同一CPU时,就浪费了CPU周期。因此,互斥锁通常用于多处理器系统,一个线程可以在一个处理器上等待,不影响其他线程的执行。
需要连续循环忙等的互斥锁,都可称为自旋锁(spin lock),如TSL指令,swap指令,单标志法
特性:
1. 需忙等,进程时间片用完才下处理机,违反让权等待
2. 优点:等待期间不用切换进程上下文,多处理机系统中,若上锁的时间短,则等待代价很低
3. 常用于多处理器系统,一个核忙等,其他核照常工作,并快速释放临界区
4. 不太适用于单处理机系统,忙等的过程中不可能解锁
在这里插入图片描述

2.3.5信号量机制

信号量机制

用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥,进程同步
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量 ,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。软件解决方案的主要问题是由进入去的各种操作无法一气呵成,因此如果能把进入区,退出区的操作都用原语实现,使这些操作能一气呵成就能避免问题。
一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为wait和sianal,括号里的信号量S其实就是函数调用时传入的一个参数。
wait,signal原语常简介为P,V操作。因此,做题的时候常把wait(S),signal(S)两个操作分别写为P(S),V(S)

信号量机制——整型信号量

用一个整数型的变量作为信号量,用来表示系统中某些资源的数量。(与普通整数变量的区别:对信号量的操作只有三种,即初始化,P操作,V操作)
Eg:某计算机系统中有一台打印机
在这里插入图片描述

信号量机制——记录型信号量

整形信号量的缺陷是存在忙等问题,因此人们又提出了记录型信号量,即用记录型数据结构表示的信号量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Eg:某计算机系统中有2台打印机,则可在初始化信号量S时将S.value的值设为2,队列S.L设置为空

在题目中,wait(S),signal(S),也可记为P(S),V(S),这对原语可用于实现系统资源的申请和释放
S.value的初值表示系统中某种资源的数目
对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S.value–,表示资源数减1,当S.value < 0时表示该类资源已分配完毕,因此进程应调用block原语进行自我阻塞(当前运行的进程从运行态->阻塞态),主动放弃处理机,并插入该类资源的等待队列S.L中。可见,该机制遵循了让权等待原则,不会出现忙等现象
对信号量的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数+1,若加1后仍是S.value<=0,表示依然有进程在等待该类资源,因此应调用wakeup原语唤醒等待队列中的第一个进程(被唤醒I进程从阻塞态->就绪态)

总结

在这里插入图片描述

2.3.6用信号量实现进程互斥,同步,前驱关系

信号量机制实现进程互斥

在这里插入图片描述

  1. 分析并发进程的关键活动,划定临界区(如:对临界资源打印机的访问就应放在临界区)
  2. 设置互斥信号量mutex,初值为1(表示进入临界区的名额)
  3. 在进入区P(mutex)——申请资源
  4. 在退出区V(mutex)——释放资源
    注:对不同的临界资源需要设置不同的互斥信号量

信号量机制实现进程同步

进程同步:要让各并发进程按要求有序地推进

  1. 分析什么地方需要实现同步关系,即必须保证一前一后执行的两个操作(或两句代码)
  2. 设置同步信号量S,初始为0
  3. 在前操作之后执行V(S)
  4. 在后操作之前执行P(S)

信号量机制实现前驱关系

其实每一对前驱关系都是一个进程同步问题(需要保证一前一后的操作)
因此

  1. 要为每一对前驱关系各设置一个同步信号量
  2. 在前操作之后对相应的同步信号量执行V操作
  3. 在后操作之前对相应的同步信号量执行P操作

总结

在这里插入图片描述

2.3.7生产者—消费者问题

问题描述

系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。(这里的产品理解为某种数据)

问题分析

生产者,消费者共享一个初始为空,大小为n的缓冲区
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
缓冲区是临界资源,各进程必须互斥的访问(互斥关系)
在这里插入图片描述

实现

在这里插入图片描述

能否改变相邻PV操作的顺序

在这里插入图片描述

总结

在这里插入图片描述

2.3.8多生产者-多消费者问题

问题描述

座子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。用PV操作实现以上过程

问题分析

  1. 关系分析。找出题目中描述的各个进程,分析他们之间的同步,互斥关系
    1. 互斥关系:对缓冲区(盘子)的访问要互斥的进行
    2. 同步关系(一前一后):
      1. 父亲将苹果翻放入盘子后,女儿才能取苹果
      2. 母亲将橘子放入盘子后,儿子才能取橘子
      3. 只有盘子为空时(盘子为空这个事件可以由儿子或女儿触发,事件发生后才允许父亲或母亲放水果),父亲或母亲才能放入水果
  2. 整理思路。根据各进程的操作流程确定P,V操作的大致顺序(互斥:在临界区前后分别PV,同步:前V后P)
  3. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始指是多少)

如何实现

在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述

吸烟者问题

问题描述

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉他,但是要卷起并抽掉一支烟,抽烟者需要三个材料:烟草,纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限的提供三种材料,供应者每次将两种材料放在桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉他,并给供应者进程一个信号告诉他完成了,供应者就会放另外两种材料在桌子上,这个过程一直重复(让三个抽烟者不停地抽烟)

问题分析

本质上这题也属于生产者—消费者问题,更详细的说应该是可生产多种产品的但生产者—多消费者

  1. 关系分析。分析同步和互斥关系
    1. 组合一:纸+胶水
    2. 组合二:烟草+胶水
    3. 组合三:烟草+纸
    4. 同步关系:组合与抽烟者一一对应
    5. 发出完成信号->供应者将下一个组合放到桌子上

如何实现

在这里插入图片描述

总结

在这里插入图片描述

2.3.10读者写者问题

问题描述

有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则有可能导致数据不一致的错误。因此要求

  1. 允许多个读者同时对文件执行读操作
  2. 只允许一个写者往文件中写信息
  3. 任一写者在完成写操作之前不允许其他读者或写者工作
  4. 写着执行写操作前,应让已有的读者和写者全部退出

问题分析

  1. 关系分析,分析同步和互斥关系
    1. 互斥关系:写进程—写进程,写进程—读进程

如何实现

在这里插入图片描述

总结

在这里插入图片描述

2.3.12 管程

为什么要引入管程

信号量机制存在的问题:编写程序困难,易出错
在这里插入图片描述

管程的定义和基本特征

管程是一种特殊的软件模块,有这些部分组成:
1. 局部于管程的共享数据结构说明
2. 对该数据结构进行操作的一组过程
3. 对局部于管程的共享数据设置初始值的语句
4. 管程有一个名字

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

引入管程的目的无非就是要更方便的实现进程互斥和同步
1. 需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
2. 需要在管程中定义用于访问这些共享数据的入口——其实就是一些函数
3. 只有通过这些特定的入口才能访问共享数据
4. 管程中有很多入口,但是每次只能开放其中一个入口,并且只能让一个进程或线程进入
5. 可以在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待;可以通过唤醒操作将等待在条件变量上的进程或线程唤醒

总结

在这里插入图片描述

2.4.1死锁的概念

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

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

死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象
饥饿:由于长期得不到想要的资源,某进程无法向前推进的现象。比如:在短进程优先(SPF)算法中,若有源源不断的短进程到来,则长进程将一直得不到处理机,从而发生长进场“饥饿”
死循环:某进程执行过程中一直挑不出来某个循环的现象。有时是因为程序逻辑bug导致的,有时是程序员故意设计的。

类型区别
死锁死锁一定是循环等待对方手里的资源导致的,因此如果有死锁现象,那至少有两个或两个以上的进程同时发生死锁。另外,发生死锁的进程一定处于阻塞态
饥饿可能只有一个进程发生饥饿。发生饥饿的进程既可能是阻塞态(如长期得不到需要的I/O设备),也可能是就绪态(长期得不到处理机)
死循环可能只有一个进程发生死循环。死循环的进程可以上处理机运行(可以是运行态),只不过无法像期待的那样顺利推进。死锁和饥饿问题是由于操作系统分配资源的策略不合理导致的,而死循环是由代码逻辑的错误导致的。死锁和解hi管理者(操作系统)的问题,死循环是被管理者的问题

共同点:都是进程无法顺利向前推进的现象(故意设计的死循环除外)

死锁产生的必要条件

产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生

  1. 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子,打印机设备)。像内存,扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这些资源)
  2. 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能自己释放
  3. 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放
  4. 循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。

注:发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分条件)
如果同类资源数大于1,则即是有循环等待,也未必发生死锁。但如果系统中每类资源都只有一个,则循环等待就是死锁的充分必要条件了。

什么时候会发生死锁

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

死锁的处理策略

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

总结

在这里插入图片描述

2.4.2死锁的处理策略—预防死锁

破坏互斥条件

互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁
如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如:SPOOLing技术。操作系统可以采用SPOOLing技术把独占设备在逻辑上改造成共享设备。比如,用SPOOLing技术将打印机改造为共享设备。
在这里插入图片描述
该策略的缺点:并不是所有的资源都可以改造成可共享使用的资源。并且为了系统安全,很多地方还必须保护这种互斥性。因此,很多时候都无法破坏互斥条件。

破坏不剥夺条件

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

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

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

破坏请求和保持条件

请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占用,此时请求进程被阻塞,但又对自己已有的资源保持不放
可以采用静态分配方法,即进程在运行前一次申请完他需要的所有资源, 在他的资源未满足前,不让他投入运行。一旦投入运行后,这些资源就一直归他所有,该进程就不会再请求别的任何资源了。
该策略实现起来简单,但也有明显的缺点:
有些资源可能只需要用很短的时间,因此如果进程的整个运行期间一直保持着所有资源,就会造成严重的资源浪费,资源利用率极低。另外,该策略也有可能导致某些进程饥饿。

破坏循环等待条件

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

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

总结

在这里插入图片描述

2.4.3 死锁的处理策略—避免死锁

安全序列,不安全状态,死锁的联系

所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个安全序列,系统就是安全状态。当然,安全序列可能有多个
如果分配了资源之后,系统都找不出任何一个安全序列,系统就进入了不安全状态。这就意味着之后可能所有进程都无法顺利的执行下去。当然,如果有进程提前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况
如果系统处于安全状态,就一定不会发生死锁。如果系统进入不安全状态,就可能发生死锁(处于不安全状态未必就是发生了死锁,但发生死锁时一定是在不安全状态)
因此可以在资源分配之前预先判断这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求。这也是银行家算法的核心思想。

总结在这里插入图片描述

死锁的处理策略—检测与解除

如果系统中既不采取预防死锁的措施,也不采取避免死锁的措施,系统就很可能发生死锁。在这种情况下,系统应当提供两个算法

  1. 死锁检测算法:用于检测系统状态,以确定系统中是否发生了死锁
  2. 死锁解除算法:当认定系统中已经发生了死锁,利用该算法可将系统从死锁状态中解脱出来

死锁的检测

为了能对系统是否已发生了死锁进行检测,必须:

  1. 用某种数据结构来保存资源的请求和分配信息
  2. 提供一种算法,利用上述信息来检测系统是否已经进入死锁状态
    如果系统中剩余的可用资源数足够满足进程的需求,那么这个进程暂时是不会阻塞的,可以顺利的执行下去
    如果这个进程执行结束了就把资源归还系统,就可能使某些正在等待资源的进程被激活,并顺利的执行下去
    相应的,这些被激活的进程执行完了之后又会归还一些资源,这样可能又会激活另外一些阻塞的进程
    如果按照上述过程分析,最终能消除所有边,就称这个图是可完全简化的。此时一定没有发生死锁(相当于能找到一个安全序列)
    如果最终不能消除所有边,那么此时就是发生了死锁。最终还连着边的那些进程就是处于死锁状态的进程

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

死锁的解除

一旦检测出死锁的发生,就应该立即解除死锁。(并不是系统中所有的进程都是死锁状态,用死锁检测算法化简资源分配图后,还连这白牛的那些进场就是死锁进程)
解除死锁的主要方法有:

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

决定对谁动手

  1. 进程优先级
  2. 已执行多长时间
  3. 还要多久能完成
  4. 进程已经使用了多少资源
  5. 进程是交互式的还是批处理式的

总结

在这里插入图片描述

3.1.1 内存的基础知识

什么是内存?有何作用?

内存可存放数据。程序执行前需要先放到内存中才能被CPU处理——缓和CPU与硬盘之间的速度矛盾
在这里插入图片描述

装入的三种方式

绝对装入

绝对装入:在编译时,如果知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照装入模块中的地址,将程序和数据转入内存。
在这里插入图片描述
绝对装入只适用于单道程序环境

可重定位装入

静态重定位:又称可重定位装入。编译,连接后的转入模块的地址时从0开始的,指令中使用的地址,数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对地址进行重定位,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)
在这里插入图片描述

动态运行时装入

动态重定位:又称动态运行时装入。编译,连接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。

从写程序到程序运行

在这里插入图片描述

连接的三种方式

  1. 静态连接:在程序运行之前,先将各目标模块及他们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。
  2. 装入时动态链接:将各目标模块装入内存时,边装入边连接的连接方式
  3. 运行时动态链接:在程序执行中需要该目标模块时,才对他进行连接。其优点是便于修改和更新,便于实现对目标模块的共享。

总结

在这里插入图片描述

3.1.2内存管理的概念

内存保护

  1. 在CPU中设置一对上下限寄存器,存放进程的上下限地址。进程的指令要访问某个地址时,CPU检查是否越界
  2. 采用重定位寄存器(又称基址寄存器)和界地址寄存器(又称限长寄存器)进行越界检查。重定位寄存器中存放的是进程的起始物理地址。界地址寄存器中存放的是进程的最大逻辑地址。

总结

在这里插入图片描述

3.1.3覆盖与交换

覆盖技术

覆盖技术的思想:将程序分为多个段(多个模块)。常用的段常驻内存,不常用的段在需要时调入内存。
内存中分为一个固定区和若干个覆盖区,需要常驻内存的段放在固定区中,调入后就不再调出(除非运行结束)。不常用的段放在覆盖区,需要用到时调入内存,用不到时调出内存。
在这里插入图片描述
必须由程序员声明覆盖结构,操作系统完成自动覆盖。缺点:对用户不透明,增加了用户编程负担。

交换技术

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

  1. 具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散匹配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续匹配方式。总之,对换区的I/O速度比文件区的更块。
  2. 交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。例如:在发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降,就可以暂停换出。
  3. 可优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调入内存后很快又被换出,有的系统还会考虑进程在内存的驻留时间。

总结

在这里插入图片描述

3.1.4连续分配管理模式

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

单一连续分配

在单一连续分配方式中,内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据:用户区用于存放用户进程相关数据。
内存中只能有一道用户程序,用户程序独占整个用户区空间。
优点:实现简单,无外部碎片。可以采用覆盖技术扩充内存;不一定需要采取内存保护(eg:早期的PC操作系统MS-DOS)
缺点:只能用于单用户,单任务的操作系统中;有内部碎片(分配给某进程的内存区域中,如果有些部分没有用上,就是内部碎片);存储器利用率低。
在这里插入图片描述

固定分区分配

20世纪60年代出现了支持多道程序的系统,为了能在内存中装入多道程序,且这些程序之间又不会相互干扰,于是将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业,这样就形成了最早的,最简单的一种可运行多道程序的内存管理方式。
分区大小相等:缺乏灵活性,但是很适用于用一台计算机控制多个相同对象的场合
分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分。
在这里插入图片描述
操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配和回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的大小,起始地址,状态(是否已分配)。
在这里插入图片描述
当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的,未分配的分区,将之分配给该程序,然后修改状态为已分配。
优点:实现简单,无外部碎片
缺点:

  1. 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能
  2. 会产生内部碎片,内存利用率低。

动态分区分配

动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态的建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的
在这里插入图片描述
把一个新作业装入内存时,需要按照一定的动态分区分配算法,从空闲分区表(或空闲分区链)中选出一个分区分配给该作业,由于分配算法对系统性能有很大的影响,因此人们对它进行了广泛的研究。

如何进行分区的分配和回收

  1. 回收区的后面有一个相邻的空闲分区
    在这里插入图片描述
  2. 回收区的前面有一个相邻的空闲分区在这里插入图片描述
  3. 回收区的前后各有一个相邻的空闲分区
    在这里插入图片描述
  4. 回收区的前后都没有相邻的空闲分区
    在这里插入图片描述
    动态分区分配没有内部碎片,但是有外部碎片
    内部碎片,分配给某进程的内存区域中,如果有些部分没有用上
    外部碎片,是指内存中的某些空闲分区由于太小而难以利用
    如果内存中空闲空间的总和本来可以满足某进程的要求,但由于进程需要的是一整块连续的内存空间,因此这些碎片不能满足进程的需求。可以通过紧凑(拼凑,Compaction)技术来解决外部碎片。

总结

在这里插入图片描述

3.1.5动态分区分配算法

动态分区分配算法:在动态分区分配方式中,当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

首次适应算法

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

最佳适应算法

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当大进程到来时能有连续的大片空间,可以尽可能的留下大片的空闲区,即。优先使用更小的空闲区。
如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

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

最坏适应算法

又称最大适应算法(Largest Fit)
算法思想:为了解决最佳适应算法的问题——即留下太多难以利用的小碎片,可以在每次分配优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。
如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区

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

邻近适应算法

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

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

首次适应算法每次都要从头查找,每次都需要检索低地址的小分区。但是这种规则也决定了当低地址部分有更小的分区可以满足需求时,会更有可能用到低地址部分的小分区,也会更有可能把高地址部分的大分区保留下来。
邻近适应算法的规则可能会导致无论低地址,高地址部分的空闲分区都有相同的概率被使用,也就导致了高地址部分的大分区更可能被使用,划分为小分区,最后导致无大分区可用。

总结

在这里插入图片描述

3.1.6基本分页存储管理的概念

什么是分页存储

将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个页框,(页框=页帧=内存块=物理块=物理页面)。每个页框有一个编号,即页框号(页框号=页帧号=内存块号=物理块号=物理页面号),页框号从0开始

将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个页或页面。每个页面也有一个编号,即页号,页号也是从0开始。

操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。

重要的数据结构—页表

为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张表。页表通常存放在PCB(进程控制块)中
在这里插入图片描述

总结

在这里插入图片描述

3.1.7基本地址变换机构

基本地址变化机构可以借助进程的页表将逻辑地址转换为物理地址
通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的始址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把他们放到页表寄存器中。
在这里插入图片描述
设页面大小为L,逻辑地址A到物理地址E的变化过程如下:

  1. 计算页号P和业内偏移量W(如果用十进制数手算,则P=A/L,W=A%L;但是在计算机实际运行时,逻辑地址结构式固定不变的,因此计算机硬件可以更快地得到二进制表示的页号,页内偏移量)
  2. 比较页号P和页表长度M,若P>=M,则产生越界中断,否则继续执行。(注:页号是从0开始的,而页表长度至少是1,因此P=M时也会越界)
  3. 页表中页号P对应的页表项地址=页表起始地址F+页号P*页表项长度,取出该页表项内容b,即为内存块号。(注意区分页表项长度,页表长度,页面大小的区别。页表长度是指这个页表总共有几个页表项,即总共有几个页;页表项长度指的是每个页表项占多大的存储空间;页面大小指的是一个页面占多大的存储空间)
  4. 计算E=b*L+W,用得到的物理地址E去访存。(如果内存块号,页面偏移量是用二进制表示的,那么把二者拼接起来就是最终的物理地址了)
    在这里插入图片描述
    在分页存储管理(页式管理)的系统中,只要确定了每个页面的大小,逻辑地址结构就确定了。因此,页式管理中地址是一维的。即,只要给出一个逻辑地址,系统就可以自动的算出页号,业内偏移量两个部分,并不需要显示的告诉系统这个逻辑地址中,业内偏移量占多少位。

总结

3.1.8 具有快表的地址变换机构

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

  1. CPU给出逻辑地址,由某个硬件算得页号,业内偏移量,将页号和快表中的所有页号进行比较
  2. 如果找到匹配的符号,说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将内存块号与业内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅需一次访存即可。
  3. 如果没有找到匹配的符号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与业内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表未命中,则访问某个逻辑地址需要两次访存(注意:在找到页表项后,应同时将其存入快表,以便后面可能得再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换)

总结

在这里插入图片描述

3.1.9两级页表

单级页表存在的问题

  1. 页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框(可以将长长的页表进行分组,使每个内存块刚好可以放入一个分组。另外,要为离散分配的页表再建立一张页表,称为页目录表,或称外层页表,或成顶层页表。)
  2. 没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面(可以在需要访问页面时才把页面调入内存(虚拟存储技术)。可以在页表项中增加一个标志位,用于表示该页面是否已经调入内存)

两级页表的原理,地址结构

在这里插入图片描述

需要注意的几个细节

  1. 若采用多级页表机制,则各级页表的大小不超过一个页面
  2. 两级页表的访存次数的分析

总结

在这里插入图片描述

3.1.10基本分段存储管理模式

进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址。
内存分配规则:以段为单位进行分配,每个段在内存占据连续空间,但各段之间可以不相邻。
在这里插入图片描述
分段系统的逻辑地址结构由段号(段名)和段内地址(段内偏移量)所组成。如:
在这里插入图片描述
段号的位数决定了每个进程最多可以分几个段,段内地址位数决定了每个段的最大长度是多少。
在上图中,若系统是按照字节寻址的,则段号占16位,因此在该系统中,每个进程最多有2^16=64K个段,段内地址占16位,因此每个段的最大长度是 2 ^ 16 = 64KB

段表

程序分为多个段,各段离散地装入内存,为了保证程序能正常运行,就必须能从物理内存中找到各个逻辑段的存放位置。为此,需为每个进程建立一张段映射表,简称“段表”。
在这里插入图片描述

  1. 每个段对应一个段表项,其中记录了该段在内存中的起始位置(又称基址)和段的长度
  2. 各个段表项的长度是相同的。例如:某系统按字节寻址,采用分段存储管理,逻辑地址结构为(段号16位,段内地址16位),因此用16位即可表示最大段长。物理内存大小为4GB(可用32位表示整个物理内存地址空间)。因此,可以让每个段表项占16+32=48位,即6B。由于段表项长度相同,因此段号可以是隐含的,不占存储空间。若段表存放的起始地址为M,则K号段对应的段表项存放的地址为M+K*6

地址变换

在这里插入图片描述

分段,分页管理的对比

页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是不可见的。
段是信息的逻辑单位。分段的主要目的是更好的满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。分段是对用户可见的,用户编程时需要显示的给出段名。
页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序
分页的用户进程地址空间是一维的,程序员只需要给出一个记忆符即可表示一个地址。
分段的用户进程的地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。
分段比分页更容易实现信息的共享和保护不能被修改的代码称为纯代码和可重入代码(不属于临界资源),这样的代码是可以共享的,可修改的代码是不能共享的(比如,有一个代码段中有很多变量,各进程并发的同时访问可能造成数据不一致)

总结

在这里插入图片描述

3.1.11段页式管理方式

优缺点分析

方式优点缺点
分页管理内存空间利用率高,不会产生外部碎片,只会有少量的业内碎片不方便按照逻辑模块实现信息的共享和保护
分段管理很方便按照逻辑模块实现信息的共享和保护如果段长过大,为其分配很大的连续空间会很不方便。另外,段式管理会产生外部碎片

分段+分页=段页式管理

在这里插入图片描述
在这里插入图片描述
段号的位数决定了每个进程最多可以分几个段
页号位数决定了每个段最大有多少页
业内偏移量决定了页面大小,内存块大小是多少

段表,页表

在这里插入图片描述

总结

在这里插入图片描述

3.2.1虚拟内存的基本概念

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

  1. 一次性:作业必须一次性全部装入内存后才能开始运行。这会造成两个问题
    1. 作业很大时,不能全部装入内存,导致大作业无法运行
    2. 当大量作业要求运行时,由于内存无法容纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降
  2. 驻留性:
    1. 一旦作业被装入内存,就会一直驻留在内存中,直至作业运行结束。事实上,在一个时间段内,只需要访问作业的一小部分数据即可正常运行,这就导致了内存中会驻留大量的,暂时用不到的数据,浪费了宝贵的内存资源。

局部性原理

  1. 时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过。不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)
  2. 空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的,并且程序的指令也是顺序的在内存中存放的)

虚拟内存的定义和特征

基于局部性原理,在程序装入时,可以将程序中的很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行。
在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。
在操作系统的管理下,在用户看来似乎有一个比实际内存大的多的内存,这就是虚拟内存。(操作系统虚拟性的一个体现,实际的物理内存大小没有变,只是在逻辑上进行了扩充)
虚拟内存有以下三个主要特征:

  1. 多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存
  2. 对换性:在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入,换出
  3. 虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量。

如何实现虚拟内存技术

虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内存管理方式基础上。
其与传统的非连续分配存储管理的主要区别是:当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序(操作系统要提供请求调页或请求调段功能)。若内存空间不够,由操作系统负责将外存中暂时用不到的信息换出到外存。(操作系统需要提供页面置换或段置换的功能)

总结

在这里插入图片描述

3.2.2请求分页管理方式

页表机制

与基本分页管理相比,请求分页管理中,为了实现请求调页,操作系统需要知道每个页面会否已经调入内存;如果还没调入,那么也需要知道该页面在外存中存放的位置
当内存空间不够时,要实现页面置换,操作系统需要通过某些指标来决定到底换出哪个页面:有的页面没有被修改过,就不用浪费时间写回外存。有的页面修改过,就需要将外存中的旧数据覆盖,因此,操作系统也需要记录各个页面是否被修改的信息。
在这里插入图片描述

缺页中断机制

在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。
此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。
如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中响应的页表项。
如果内存中没有空闲块,则由页面置换算法选择一个页面被淘汰,若该页面在内存期间被修改过,则要将其写回外存。未修改过的页面不用写回外存。

缺页中断时因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断。
一条指令在执行期间,可能产生多次缺页中断。(如copy A to B)

补充细节:

  1. 只有写指令才需要修改“修改位”。并且,一般来说只需修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表。这样可以减少访存次数
  2. 和普通的中断一样,缺页中断处理依然需要保留CPU现场
  3. 需要用某种页面置换算法来决定下一个换出页面
  4. 换入/换出页面都需要启动慢速的I/O操作。可见,如果换入/换出太频繁,会有很大的开销。
  5. 页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。
    在这里插入图片描述

总结

在这里插入图片描述

3.2.3页面置换算法

最佳置换算法(OPT)

最佳置换算法(OPT,Optimal):每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。
最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。

先进先出置换算法(FIFO)

先进先出置换算法(FIFO):每次选择淘汰的页面是最早进入内存的页面
实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。队列的最大长度取决于系统为进程分配了多少个内存块。
Belady异常—— 当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。
只有FIFO算法会产生Belady异常,另外,FIFO算法虽然实现简单,但是该算法与进程运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此。算法性能差。

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

最近最久未使用置换算法(LRU,least recently used):每次淘汰的页面是最近最久未使用的页面
实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的事件t。当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面
在这里插入图片描述

时钟置换算法(CLOCK)

最佳置换算法性能最好,但无法实现;FIFO算法实现简单,但算法性能差。LRU算法性能好,但是实现起来需要专门的硬件支持,算法开销大。
时钟置换算法是一种性能和开销较均衡的算法,又称为CLOCK算法或最近未用算法(NRU,Not Recently Used)
简单的CLOCK算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需要检查页的访问位。如果是0,就选择该页换出;如果是1,则将他置为0,暂不换出,继续检查下一个页面,若第一轮扫描中所有页面都是1,则将这些页面额访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)

改进型的时钟置换算法

简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。
因此,除了考虑第一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。修改为=0,表示页面没有被修改过;修改为=1,表示页面被修改过。

算法规则:将所有可能被置换的页面排成一个循环队列
第一轮:从当前位置开始扫到第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位
第二轮:若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。本轮将所有扫描过的帧访问位设为0。
第三轮:若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位
第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。
由于第二轮已将所有的帧的访问位设为0,因此经过第三轮,第四轮扫描一定会有一个帧被选中,因此改进型CLOCK置换算法选择淘汰页面最多会进行四轮扫描。

总结

在这里插入图片描述

3.2.4页面分配策略,抖动,工作集

页面分配,置换策略

驻留集:指请求分页存储管理中给进程分配的物理块的集合。在采用了虚拟存储技术的系统中,驻留集大小一般小于进程的总大小。
若驻留集太小,会导致缺页频繁,系统要花大量的时间来处理缺页,实际用于进程推进的时间很少;驻留集太大,又会导致多道程序并发度下降,资源利用率降低。所以应该选择一个合适的驻留集大小。

固定分配:操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变。即,驻留集大小不变。
可变分配:先为每个进程分配一定数目的物理块,在进程运行期间,可根据情况做适当的增加或减少。即,驻留集大小不变。

局部置换:发生缺页时只能选进程自己的物理块进行置换
全局置换:可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程。

在这里插入图片描述

固定分配局部置换:系统为每次进程分配一定数量的物理块,在整个运行期间都不改变。若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面。这种策略的缺点是:很难在刚开始就确定应为每个进程分配多少个物理块才算合理。(采用这种策略的系统可以根据进程的大小,优先级,或是根据程序员给出的参数来确定为一个进程分配的内存快数)

可变分配全局置换:刚开始会为每个进程分配一定数量的物理块。操作系统会保持一个空闲物理块队列。当某进程发生缺页时,从空闲物理块中取出一块分配给该进程;若已无空闲物理块,则可选择一个未锁定的页面换出外存,再将该物理块分配给缺页的进程。采用这种策略时,只要某进程发生缺页,都将获得新的物理块,仅当空闲物理块用完时,系统才选择一个未锁定的页面调出。被选择调出的页可能是系统中任何一个进程中的页,因此这个被选中的进程拥有的物理块会减少,缺页率会增加。

可变分配局部置换:刚开始会为每个进程分配一定的数量的物理块。当某进程发生缺页时,只允许从该进程自己的物理块中选出一个进行换出外存。如果进程在运行中频繁地缺页,系统会为该进程多分配几个物理块,直至该进程缺页率趋势适当程序;反之,如果进程在运行中缺页率特别低,则可适当减少分配该进程的物理块。

可变分配全局置换:只要缺页就给分配新物理块
可变分配局部置换:要根据发生缺页的频率来动态地增加或减少进程的物理块

何时调入页面

  1. 预调页策略:根据局部性原理,一个调入若干个相邻的页面可能比一次调入一个页面更高效。但如果提前调入的页面中大多数都没被访问过,则又是低效的。因此可以预测不久之后可能访问到页面,将他们预先调入内存,但目前预测成功率只有50%左右。故这种策略主要用于进程的首次调入,由程序员指出应该先调入哪些部分
  2. 请求调页策略:进程在运行期间发现缺页时才将所缺页面调入内存。由这种策略调入的页面一定会被访问到,但由于每次只能调入一页,而每次调页都要磁盘I/O操作,因此I/O开销较大。

从何处调入页面

在这里插入图片描述

  1. 系统拥有足够的对换区空间:页面的调入,调出都是在内存与对换区之间进行,这样可以保证页面的调入,调出速度很快。在进程运行前,需将进程相关的数据从文件区复制到对换区。
    在这里插入图片描述

  2. 系统中缺少足够的对换区空间:凡是不会被修改的数据都直接从文件区调入,由于这些页面虬被修改,因此换出时不必写回吸盘,下次需要时再从文件区调入即可。对于可能被修改的部分,换出时需写回磁盘对换区,下次需要时再从对换区调入。

  3. UNIX方式:运行之前进程有关的数据全部放在文件区,故未使用过的页面,都可以从调入。若被使用过的页面需要换出,则写回对换区,下次需要时从对换区调入。

抖动(颠簸)现象

刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出内存,这种频繁的页面调度行为称为抖动,或颠簸。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理快数(分配给进程的物理块不够)

工作集

驻留集:指请求分页存储管理中给进程分配的内存卡的集合
工作机:指在某段时间间隔里,进程实际访问页面的集合

操作系统会根据窗口尺寸来算出工作集。例:
某进程的页面访问序列如下,窗口尺寸为4,各时刻的工作集为?
在这里插入图片描述
工作集大小可能小于窗口尺寸,实际应用中,操作系统可以统计进程的工作集大小,根据工作集大小给进程分配若干内存块。如:窗口尺寸为5,经过一段时间的检测发现某进程的工作集最大为3,那么说明该进程有很好额局部性,可以给这个进程分配3个以上的内存块即可满足进程的运行需要。一般来说,驻留集的大小不能小于工作集大小,否则进程运行过程中将频繁缺页。

扩展:基于局部性原理可知,进程在一段时间内访问的页面与不久之后会访问的页面是有相关性的。因此,可以根据进程近期访问的页面集合(工作集)来设计一种页面置换算法——选择一个不在工作集中的页面进行淘汰。

总结

在这里插入图片描述

3.2.5内存映射文件

内存映射文件——操作系统向上层提供程序眼提供的功能(系统调用)

  1. 方便程序员访问文件数据
  2. 方便多个进程共享同一个文件

传统文件的访问方式

  1. open系统调用——打开文件
  2. seek系统嗲用——将读写指针移到某个为止
  3. read系统调用——从读写指针所指位置读入若干数据(从磁盘读入内存)
  4. write系统调用——将内存中的指定数据,写回磁盘(根据读写指针确定要写回什么位置)

内存映射文件(Memory-Mapped Files)

内存映射文件的访问方式

  1. open系统调用——打开文件
  2. mmap系统调用——将文件映射到进程的虚拟地址空间
    1. 以访问内存的方式访问文件数据
    2. 文件数据的读入,写出由操作系统自动完成
    3. 进程关闭文件时,操作系统自动将文件被修改的数据写回磁盘
      在这里插入图片描述
      多个进程可以映射同一文件,实现共享
      在物理内存中,一个文件对应同一份数据,当一个进程修改文件数据时,另一个进程可以立马看到

总结

在这里插入图片描述

4.1.1 初识文件管理

文件的属性

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

文件内部的数据应该怎样组织起来?

在这里插入图片描述

文件之间应该怎样组织起来

在这里插入图片描述

操作系统应该为上层提供哪些功能

在这里插入图片描述

总结

在这里插入图片描述

4.1.2文件的逻辑结构

所谓“逻辑结构”就是指在用户看来,文件内部的数据应该是如何组织起来的。而物理结构指的是在操作系统看来,文件的数据是如何存放在外存中的。

无结构文件

按文件是否有结构分类,可以分为无结构文件,有结构文件两种
无结构文件:文件内部的数据就是一系列二进制流或字符流组成。又称流式文件。如:Windows操作系统中的.txt文件。
有结构文件:由一组详细的记录组成,又称记录式文件。每条记录又若干个数据组成。如:数据库表文件。一般来说,每条记录有一个数据项可作为关键字(作为识别不同记录的ID)根据各条记录的长度(占用的存储空间)是否相等,又可分为定长记录和可变长记录两种。

顺序文件

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

索引文件

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

索引顺序文件

索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是:并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项。
在这里插入图片描述

多级索引顺序文件

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

总结

在这里插入图片描述

4.1.3 文件目录

文件控制块

在这里插入图片描述
在这里插入图片描述

目录结构——单级目录结构

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

目录结构——两级目录结构

早期的多用户操作系统,采用两级目录结构。分为主文件目录(MFD,Master File Directory)和用户文件目录(UFD,User File Directory)。
在这里插入图片描述

目录结构——多级目录结构

用户(或用户进程)要访问某个文件时要用文件路径名标识文件,文件路径名是个字符串。各级目录之间用“/”隔开。从根目录出发的路径称为绝对路径。
系统根据绝对路径一层一层地找到下一级目录。刚开始从外存读入根目录的目录表:找到“照片”目录的存放位置后,从外存读入对应的目录表;再找到相应的目录的存放位置,再从外存读入对应目录表;最后才找到文件的存放位置。整个过程需要3次磁盘I/O操作。
可见。引入当前目录和相对路径后,磁盘的I/O的次数减少了。这就提升了访问文件的效率。
树形目录结构可以很方便地对文件进行分类,层次结构清晰,也能够有效的进行文件的管理和保护。但是,树形结构不便于实现文件的共享为此,提出了无环图目录结构。

目录结构——无环图目录结构

在这里插入图片描述
可以用不同的文件名指向同一个文件,甚至可以指向同一个目录(共享同一目录夏的所有内容)
需要为每个共享结点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。用户提出删除结点的请求时,只是删除该用户的FCB,并使共享计数器减1,并不会直接删除共享结点。
只有共享计数器减为0时,才删除结点。
注意:共享文件不同于复制文件。在共享文件中,由于各用户指向的是同一个文件,因此只要其中一个用户修改了文件数据,那么所有用户都可以看到文件数据的变化。

索引结点(FCB的改进)

在这里插入图片描述

总结

在这里插入图片描述

4.1.4文件的物理结构(上)

文件块,磁盘块

在这里插入图片描述
类似于内存分页,磁盘中的存储单元也会被分为一个个“块/磁盘块/物理块”。很多操作系统中,磁盘块的大小与内存块,页面的大小相同。

在内存管理中,进程的逻辑空间被分为一个一个页面
同样的,在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为一个一个的文件块。于是文件的逻辑地址页可以表示为(逻辑块号,块内地址)的形式。

文件分配方式——连续分配

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

用户给出要访问的逻辑块号,操作系统找到该文件对应的目录项(FCB)…
物理块号=起始块号+逻辑块号
当然,还需要检查用户提供的逻辑块号是否合法(逻辑快号 >= 长度就不合法)(可以直接算出逻辑块号对应的物理块号,因此连续分配支持顺序访问和直接访问(即随机访问))

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

4.1.4文件的物理结构(下)

文件分配方式——索引分配

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

注:在显示链接的链式分配方式中,文件分配表FAT是一个磁盘对应一张。而索引分配方式中,索引表是一个文件对应一张。

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

  1. 链接方案:如果索引表太大,一个索引块装不下,那么可以将多个索引块链接起来存放。
  2. 多层索引:建立多层索引(原理类似于多级页表)。使第一层索引块指向第二层的索引块。还可根据文件大小的要求再建立第三层,第四层索引块。
  3. 混合索引:多种索引分配方式的结合。例如,一个文件的项级索引表中,既包含直接地址索引(直接指向数据块),又包含一级间接索引(指向单层索引表),还包含两级间接索引(指向两层索引表)。

总结

在这里插入图片描述
在这里插入图片描述

4.1.6 文件存储空间管理

存储空间的划分与初始化

安装Windows操作系统的时候,一个毕竟步骤时——为磁盘分区(C盘,D盘,E盘)(存储空间的划分:将物理磁盘划分为一个个文件卷(逻辑卷,逻辑盘))
在这里插入图片描述

存储空间管理——空闲表法

如何分配磁盘块:与内存管理中的动态分区分配很类似,为一个文件分配连续的存储空间。同样可采用首次适应,最佳适应,最坏适应等算法来决定要为文件分配哪个区间。

如何回收磁盘块:与内存管理中的动态分区分配很类似,当回收某个存储区时需要有四种情况——

  1. 回收区的前后都没有相邻空闲区
  2. 回收区的前后都是空闲区
  3. 回收区的前面是空闲区
  4. 会后去的后面是空闲区。
    总之,回收时需要注意表项的合并问题。

存储空间管理——空闲链表法

  1. 空闲盘块链——以盘块为单位组成一条空闲链
    1. 操作系统保存着链头,链尾指针
    2. 如何分配:若某文件申请K个盘块,则从链头开始依次摘下K个盘块分配,并修改空闲链的链头指针
    3. 如何回收:回收的盘块依次挂到链尾,并修改空闲链的链尾指针
  2. 空闲盘区链——以盘区为单位组成一条空闲链
    1. 操作系统保存着链头,链尾的指针
    2. 如何分配:若某文件申请K个盘块,则可以采用首次适应,最佳适应等算法,从链头开始检索,按照算法规则找到一个大小符合要求的空闲盘区,分配给文件。若没有合适的连续空闲块,也可以将不同盘区的盘块同时分配给一个文件,注意分配后可能要修改响应的链指针,盘区大小等数据。
    3. 如何回收:若回收区和某个空闲盘区相邻,则需要将回收区合并到空闲盘区中。若回收区没有和任何空闲区相邻,将回收区作为单独的一个空闲盘区挂到链尾。

存储空间管理——位示图法

位示图:每个二进制对应一个盘块。在本例中,“0”代表盘块空闲,“1”代表盘块已分配。位示图一般用连续的字来表示,如本例中一个字的字长是16位,字中的每一位对应一个盘块。因此可以用(字号,位号)对应一个盘块号。当然有的题目中也描述为(行号,列号)
在这里插入图片描述
如何分配:若文件需要K个块,顺序扫描位示图,找到K个相邻或不相邻的“0”,根据字号,位号算出对应的盘块号,将相应盘块分配给文件,将相应位设置为“1”
如何回收:根据回收的盘块号计算出对应的字号,位号,将相应二进制位设为“0”

存储空间管理——成组链接法

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

总结

在这里插入图片描述

4.1.7文件的基本操作

创建文件

进行Create系统调用时,需要提供的几个主要参数
1. 所需的外存大小(如:一个盘块,即1KB)
2. 文件存放路径(“D:/Demo”)
3. 文件名

操作系统在处理Create系统调用时,主要做了两件事
1. 在外存中找到文件所需的空间(组合上小节所学的空闲链表法,位示图,成组链接法等管理策略,找到空闲空间)
2. 根据文件存放路径的信息找到该目录对应的目录文件,在目录中创建该文件对应的目录项。目录项中包含了文件名,文件在外存中的存放位置等信息。

删除文件

进行Delete系统调用时,需要提供的几个主要参数
1. 文件存放路径
2. 文件名

操作系统在处理Delete系统调用时,主要做了几件事
1. 根据文件存放路径找到相应的目录文件,从目录中找到文件名对应的目录项
2. 根据该目录项记录的文件在外存的存放位置 文件大小等信息,回收文件占用的磁盘块。(回收磁盘块时,根据空闲表法,空闲链表法,位示图法等管理策略的不同,需要做不同的处理)
3. 从目录表中删除文件对应的目录项

打开文件

在很多操作系统中,在对文件进行操作之前,要求用户先使用open系统调用打开文件,需要提供的几个主要参数
1. 文件存放路径
2. 文件名
3. 要对文件的操作类型(r:只读,rw:读写等)

操作系统在处理open系统调用时,主要做了几件事
1. 根据文件存路径找到相应的目录文件,从目录中找到文件名对应的目录项,并检查该用户是否有指定的操作权限。
2. 将目录项复制到内存中的打开文件表中。并将对应表目的编号返回给用户。之后用户使用打开文件表的编号来指明要操作的文件。
在这里插入图片描述

关闭文件

进程使用完文件后,要关闭文件,操作系统在处理Close系统调用时,主要做了几件事

  1. 将进程的打开文件表相应表项删除
  2. 回收分配给该文件的内存空间等资源
  3. 系统打开文件表的打开计数器count减1,若count=0,则删除对应表项

读文件

进程使用read系统调用完成写操作。需要指明是哪个文件(在支持打开文件操作的系统中,只需要提供文件在打开文件表中的索引号即可),还需要指明要读入多少数据,指明读入的数据要放在内存中的什么位置。
操作系统在处理read调用时,会从读指针指向的外存中,将用户指定大小的数据读入用户指定的内存区域中。

写文件

进程使用write系统调用完成写操作,需要指明是哪个文件(在支持打开文件的操作系统中,只需要提供文件在打开文件表中索引号即可),还需要指明要写出多少数据,写回外存的数据放在内存中的什么位置
操作系统在处理write系统调用时,会从用户指定的内存区域中,将指定大小的数据写回写指针指向的外存。

总结

在这里插入图片描述

4.1.8文件共享

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

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

知识回顾:索引结点,是一种文件目录瘦身策略。由于检索文件时只需用到文件名,因此可以将除了文件名之外的其他信息放到索引结点汇中。这样目录项就只需要包含文件名,索引节点指针。
在这里插入图片描述
索引结点中设置一个链接计数变量count,用于表示链接到本索引结点上的用户目录项数
若count=2,说明此时有两个用户目录项链接到该索引结点上, 或者说是有两个用户在共享此文件。若某个用户决定“删除”该文件,则只是要把用户目录中与该文件对应的目录项删除,且索引结点的count值减一。
若count>0,说明还有别的用户要使用该文件,暂时不能把文件数据删除,否则会导致指针悬空
当count=0时系统负责删除文件。

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

在这里插入图片描述
当User3访问“ccc”时,操作系统判断文件“ccc”属于Link类型文件,于是会根据其中记录的路径层层查找目录,最终找到User1的目录表红的“aaa”选项,于是就找到了文件1的索引结点。

总结

在这里插入图片描述

4.1.9文件保护

口令保护

为文件设置一个口令(口令一般存放在文件对应的FCB或索引结点中。用户访问文件前需要先输入口令,操作系统会将用户提供的口令与FCB中存储的口令进行对比,如果正确,则允许该用户访问文件),用户请求访问该文件时必须提供口令

优点:保存口令的空间开销不多,验证口令的时间开销也很小
缺点:正确的口令存放在系统内部,不够安全。

加密保护

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

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

访问控制

在每个文件的FCB(或索引结点)中增加一个访问控制列表(Access-Control List,ACL),该表中记录了各个用户可以对该文件执行哪些操作。

精简的访问列表:以“组”为单位,标记各“组”用户可以对文件执行哪些操作。
如:分为系统管理员,文件主,文件主的伙伴,其他用户几个分组。
当某用户想要访问文件时,系统会检查该用户所属的分组是否有相应的访问权限。

总结

在这里插入图片描述

4.3.1 文件系统的层次结构

在这里插入图片描述

4.3.2 文件系统的全局结构(布局)

原始磁盘

在这里插入图片描述

物理格式化后

在这里插入图片描述
物理格式化,即低级格式化——划分扇区,检测坏扇区,并用备用扇区替换坏扇区。

逻辑格式化后

在这里插入图片描述
逻辑格式化后,磁盘分区(分卷Volume),完成各分区的文件系统初始化。逻辑格式化后,灰色部分就有实际数据了,白色部分还没有数据。

文件系统在内存中的结构

在这里插入图片描述
注:近期访问过的目录文件会缓存在内存中,不用每次都从磁盘读入,这样可以加快目录检索速度。

open系统调用打开文件的背后过程

在这里插入图片描述

4.1.3 虚拟文件系统

普通的文件系统

在这里插入图片描述

虚拟文件系统

在这里插入图片描述
虚拟文件系统的特点:

  1. 向上层用户进程提供统一标准的系统调用接口,屏蔽底层具体文件系统的实现差异。
  2. VFS要求下层的文件系统必须实现某些规定的函数功能,如:open/read/write。一个新的文件系统想要在某操作系统上被使用,就必须满足该操作系统VFS的要求。
  3. 每打开一个文件,VFS就在主存中新建一个vnode,用统一的数据结构表示文件,无论该文件存储在哪个文件系统。

存在的问题:不同的文件系统,表示文件的数据结构各不相同。打开文件后,其在内存中的表示就不同。

在这里插入图片描述

文件系统挂载(mounting)

文件系统挂载(mounting),即文件系统安装/装载——如何将一个文件系统挂载到操作系统中?
文件系统挂载要做的事:

  1. 在VFS中注册信挂载的文件系统。内存中的挂载表(mount table)包含每个文件系统的相关信息,包括文件系统类型,容量大小等。
  2. 新挂载的文件系统,要向VFS提供一个函数地址列表
  3. 将新文件系统加到挂载点(mount point),也就是将新文件系统挂载在某个父目录下。

5.1.1.1 I-O设备的概念和分类

什么是I/O设备

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

UNIX系统将外部设备抽象为一种特殊的文件,用户可以使用与文件操作相同的方式对方式对外部设备进行操作。

I/O设备的分类——按使用特性

在这里插入图片描述

I/O设备的分类——按传输速率分类

在这里插入图片描述

I/O设备的分类——按信息交换的单位分类

在这里插入图片描述

总结

在这里插入图片描述

5.1.2.1 I-O控制器

I/O设备的机械部件

I/O设备的机械部件主要用来执行具体I/O操作,如我们能看得见摸得着的鼠标/键盘的按钮
I/O设备的电子部件通常是一块插入主板扩充槽的印刷电路板

I/O设备的电子部件(I/O控制器)

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

I/O控制器的组成

在这里插入图片描述
注:

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

内存映像I/O 与 寄存器独立编址

在这里插入图片描述

总结

在这里插入图片描述

5.1.3.1 IO控制方式

程序直接控制方式

在这里插入图片描述
在这里插入图片描述

  1. 完成一次读写操作的流程,如上图
  2. CPU干预的频率:很频繁,I/O操作开始之前,完成之后需要CPU介入,并且在等待I/O完成的过程中CPU需要不断的轮询检查。
  3. 数据传送的单位:每次读写一个字
  4. 数据的流向:
    1. 读数据(数据输入):I/O设备->CPU(指的是CPU的寄存器)->内存
    2. 写操作(数据输出):内存->CPU.–>I/O设备
    3. 每个字的读/写都需要CPU的帮助
  5. 主要缺点和主要优点
    1. 优点:实现简单。在读写指令之后,加上实现循环检查的一系列指令即可(因此才成为程序直接控制方式)
    2. 缺点:CPU和I/O设备只能串行工作,CPU需要一直轮询检查,长期处于忙等状态,CPU利用率低。

中断驱动方式

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

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

  1. 完成一次读写操作的流程,如上图
  2. CPU干预的频率:每次I/O操作开始之前,完成之后需要CPU介入。等待I/O完成的过程中CPU可以切换到别的进程执行
  3. 数据传送的单位:每次读写一个字
  4. 数据的流向:
    1. 读数据(数据输入):I/O设备->CPU(指的是CPU的寄存器)->内存
    2. 写操作(数据输出):内存->CPU.–>I/O设备
    3. 每个字的读/写都需要CPU的帮助
  5. 主要缺点和主要优点
    1. 优点:与程序直接控制方式相比,在中断驱动方式中,I/O控制器会通过中断信号主动报告I/O已完成,CPU不再需要不听的轮询.CPU和I/O设备可并行工作,CPU利用率得到明显提升
    2. 缺点:每个字在I/O设备与内存之间的传输都需要经过CPU。而频繁的中断处理会消耗掉较多的CPU时间。

DMA方式

与终端驱动方式相比,DMA方式(Direct Memory Access,直接存储器存取。主要用于块设备的I/O控制)有这样几个改进:

  1. 数据的传送单位是块,不再是一个字一个字的传送。
  2. 数据的流向是从设备直接放入内存,或者从内存直接到设备。不再需要CPU作为快递小哥。
  3. 仅在传送一个或者多个数据块的开始时,才需要CPU干预。

在这里插入图片描述

DR(Data Register,数据暂存器):暂存从设备到内存,或从内存到设备的数据
MAR(Memory Access Register,内存地址寄存器):在输入时,MAR表示数据应放到内存中的什么位置;输出时MAR表示要输出的数据放在内存中的什么位置。
DC(Data Counter,数据计数器):表示剩余到读/写的字节数
CR(Command Register,命令/状态寄存器):用于存放CPU发来的I/O命令,或设备的状态信息。

CPU干预的频率:仅在传送一个或多个数据块的开始和结束时,才需要CPU干预
数据传送的单位:每次读写一个或多个块(注意:每次读写的只能是连续的多个块,且这些块读入内存后在内存中也必须是连续的)。
数据的流向:
1. 读操作(数据输入):I/O设备->内存
2. 写操作(数据输出):内存->I/O设备
主要优点和缺点
1. 优点:输出传输以块为单位,CPU介入频率进一步降低。数据的传输不再需要先经过CPU再写入内存,数据传输效率进一步增加。CPU和I/O设备的并行性得到提升。
2. 缺点:CPU每发出一条I/O指令,只能读写一个或多个连续的数据块。如果要读写多个离散存储的数据块,或者要将数据分别写到不同的内存区域时,CPU要分别发出多条I/O指令,进行多次中断处理才能完成。

通道控制方式

通道:一种硬件,可以理解为是“弱鸡版的CPU(与CPU相比,通道可以执行的指令很单一,并且通道程序是放在主机内存中的,也就是说通道与CPU共享内存)”。通道可以识别并执行一系列通道命令。

在这里插入图片描述

在这里插入图片描述

  1. 完成一次读写操作的流程,如上图
  2. CPU干预的频率:极低,通道会根据CPU的指示执行响应的通道程序,只有完成一组数据块的读写后才会发出中断信号,请求CPU干预。
  3. 数据传送的单位:每次读写一组数据块
  4. 数据的流向:
    1. 读数据(数据输入):I/O设备->内存
    2. 写操作(数据输出):内存->I/O设备
    3. 每个字的读/写都需要CPU的帮助
  5. 主要缺点和主要优点
    1. 优点:CPU,通道,IO设备可并行工作,资源利用率很高
    2. 缺点:实现复杂,需要专门的通道硬件支持。

总结

在这里插入图片描述

5.1.4.1 IO软件层次结构

在这里插入图片描述

用户层软件

在这里插入图片描述
Windows系统调用向外提供一系列系统调用,但是由于系统调用的格式严格,使用麻烦,因此在用户层上封装了一系列更方便的库函数接口供用户使用(Windows API)

设备独立性软件

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

  1. 向上层提供统一的调用接口(如read/write系统调用)
  2. 设备的保护:原理和文件的保护类似。设备被看做是一种特殊的文件,不同用户对各个文件的访问的访问权限是不一样的,同理,对设备的访问权限也不一样。
  3. 差错处理:设备独立性软件需要对一些设备的错误进行处理
  4. 设备的分配和回收
  5. 数据缓冲区管理:可以通过缓冲技术屏蔽设备之间数据交换单位大小和传输速度的差异
  6. 建立逻辑设备名到物理设备名的映射关系:根据设备类型选择调用响应的驱动程序:用户或用户层次的软件发出IO操作相关系统调用的系统调用时,需要指明此次操作的IO设备的逻辑设备名。设备独立性软件通过逻辑设备表(LUT,Logical Unit Table)来确定逻辑设备对应的物理设备,并找到该设备对应的设备驱动程序,
    在这里插入图片描述
    操作系统可以采用两种方式管理逻辑设备表(LUT):
    1. 第一种方式,整个系统只设置一张LUT,这就意味着所有用户不能使用相同的逻辑设备名,因此这种方式只适用于单用户操作系统
    2. 第二种方式,为每个用户设置一张LUT,各个用户使用的逻辑设备名可以重复,适用于多用户操作系统。系统会在用户登录时建立一个用户管理进程,而LUT就存放在用户管理进程的PCB中。

为什么不同的设备需要不同的设备驱动程序

不同设备的内部硬件特性不同,这些特性只有厂家才知道,因此厂家须提供与设备相对应的驱动程序,CPU执行驱动程序的指令序列,来完成设置设备寄存器,检查设备状态等工作。

设备驱动程序

在这里插入图片描述

中断处理程序

当IO任务完成时,IO控制器会发送一个中断信号,系统会根据中断信号类型找到相应的中断处理程序并执行。中断处理程序的处理流程如下:
在这里插入图片描述

总结

在这里插入图片描述

5.1.5 输入输出应用程序接口和驱动程序接口

输入/输出应用程序接口

在这里插入图片描述

阻塞/非阻塞IO

阻塞I/O:应用程序发出IO系统调用,进程需转为阻塞态等待
eg:字符设备接口——从键盘读一个字符get
非阻塞I/O:应用程序发出I/O系统调用,系统调用可迅速返回,进程无需阻塞等待。
eg:块设备接口——往磁盘写数据write

设备驱动程序接口

在这里插入图片描述
在这里插入图片描述

5.2.1 IO核心子系统

IO调度

I/O调度:用某种算法确定一个好的顺序来处理各个I/O请求。
如:磁盘调度。当多个磁盘IO请求到来时,用某种调度算法确定满足IO请求的顺序。

设备保护

操作系统需要实现文件保护功能,不同的用户对各个文件有不同的访问权限(如:只读,读和写)
在UNIX系统中,设备被看做是一种特殊的文件,每个设备也会有对应的FCB。当用户请求访问某个设备时,系统根据FCB记录中记录的信息来判断用户是否有响应的访问权限,以此实现“设备保护”的功能。

5.2.2 假脱机技术

什么是脱机技术

手工操作阶段:主机直接从I/O设备来获得数据,由于设备速度慢,主机速度很快。人机速度矛盾明显,主机要浪费很多时间来等待设备。
批处理阶段引入了脱机输入/输出技术(用磁带完成):引入脱机技术后,缓解了CPU与慢速IO设备的速度矛盾。另一方面,即使CPU在忙碌,也可以提前将数据输入到磁带;即是慢速的输出设备正在忙碌,也可以提前将数据输出到磁带。
在这里插入图片描述

假脱机技术——输入井和输出井

“假脱机技术”,又称“SPOOLing技术”是用软件的方式模拟脱机技术。SPOOLing系统的组成如下:
在这里插入图片描述

共享打印机原理分析

当多个用户进程提出输出打印的请求时,系统会答应他们的请求,但是并不是真正的把打印机分配给他们,而是由假脱机管理进程为每个进程做两件事:

  1. 在磁盘输出井中为进程申请一个空闲缓冲区(也就是说,这个缓冲区是在磁盘上的),并将要打印的数据送入其中
  2. 为用户进程申请一张空白的打印请求表,并将用户的打印请求填入表中(其实就是用来说明用户的打印数据存放位置等信息的),再将该表挂到假脱机文件队列上。
    当打印机空闲时,输出进程会从文件队列的队头取出一张打印请求表,并根据表中的要求将要打印的数据从输出井传送到输出缓冲区,再输出到打印机进行打印。用这种方式可依次处理完全部的打印任务。
    虽然系统中只有一个打印机,但每个进程提出打印请求时,系统都会为在输出井中为其分配一个缓冲区(相当于分配了一个逻辑设备),使每个用户进程都觉得自己在独占一台打印机,从而实现对打印机的共享。
    SPOOLing技术可以把一台物理设备虚拟成逻辑上的多个设备,可将独占式设备改造成共享设备。

总结

在这里插入图片描述

5.2.3 设备的分配和回收

设备分配时应考虑的因素

  1. 设备的固有属性可分为三种:独占设备,共享设备,虚拟设备
    1. 独占设备:一个时段只能分配给一个进程(如打印机)
    2. 共享设备:可同时分配给多个进程使用(如磁盘),各进程往往是宏观上同时共享使用设备,而微观上来交替使用
    3. 虚拟设备:采用SPOOLing技术将独占设备改造成虚拟的共享设备,可同时分配给多个进程使用(如SPOOLing技术实现的共享打印机)
  2. 设备分配算法
    1. 先来先服务
    2. 优先级高者优先
    3. 短任务优先
  3. 从进程运行的安全性上考虑,设备分配有两种方式
    1. 安全分配方式:为进程分配一个设备后就将进程阻塞(一个时段内每个进程只能使用一个设备,优点:破坏了请求和保持条件,不会死锁、缺点:对于一个进程来说,CPU和IO设备只能串行工作),本次IO完成后才将进程唤醒(eg:考虑进程请求打印机打印输出的例子)
    2. 不安全分配方式:进程发出IO请求后,系统为其分配IO设备,进程可继续执行,之后还可以发出新的IO请求。只有某个IO请求得不到满足时才将进程阻塞。(一个进程可以同时使用多个设备,优点:进程的计算任务和IO任务可以并行处理,使进程迅速推进。缺点:有可能发生死锁(死锁避免,死锁的检测和解除))

静态分配和动态分配

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

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

“设备,控制器,通道”之间的关系:
在这里插入图片描述
一个通道可控制多个设备控制器,每个设备控制器可控制多个设备。

设备控制表(DCT):系统为每个设备配置一张DCT,用于记录设备情况
在这里插入图片描述
注: “进程管理”章节中曾经提到过“系统会根据阻塞原因的不同”,将进程PCB挂到不同的阻塞队列中。

控制器控制表(COCT):每个设备控制器都会对应一张COCT。操作系统根据COCT的信息对控制器进程操作和管理。
在这里插入图片描述

通道控制表(CHCT):每个通道都会对应一张CHCT。操作系统根据CHCT的信息对通道进行操作和管理。
在这里插入图片描述

系统设备表(SDT):记录了系统中全部设备的情况,每个设备对应一个表目。
在这里插入图片描述

设备分配的具体步骤

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

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

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

设备分配步骤的改进

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

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

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

总结

在这里插入图片描述

5.2.4 缓冲区管理

什么是缓冲区

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

缓冲区有什么作用

  1. 缓和CPU与IO设备之间速度不匹配的矛盾
  2. 减少对CPU的中断频率,放宽对CPU中断相应时间的限制
  3. 解决数据粒度不匹配的问题
  4. 提高CPU与IO设备之间的并行性

单缓冲

假设某用户进程请求某种块设备读入若干块的数据。若采用单缓冲的策略,操作系统会在主存中为其分配一个缓冲区(若题目没有特别说明,一个缓冲区的大小就是一个块)

注:当缓冲区数据非空时,不能往缓冲区冲入数据,只能从缓冲区将数据冲出:当缓冲区为空时,可以往缓冲区冲入数据,单必须把缓冲区充满以后,才能从缓冲区把数据传出

双缓冲

假设某用户进程请求某种块设备读入若干块的数据。若采用双缓冲的策略,操作系统会在主存中为其分配两个缓冲区(若题目没有特别说明,一个缓冲区的大小就是一个块)

若采用双缓冲策略,处理一个数据块的平均耗时为Max(T,C+M)

使用单/双缓冲在通信时的区别

两台机器之间通信时,可以配置缓冲区用于数据的发送和接受。
在这里插入图片描述
显然,若两个相互通信的机器只设置单缓冲区,在任一时刻只能实现数据的单向传输。
在这里插入图片描述

若两个相互通信的机器设置双缓冲区,则同一时刻可以实现双向的数据传输

循环缓冲区

将多个大小相等的缓冲区链接成一个循环队列。
在这里插入图片描述

缓冲池

缓冲池由系统中共用的缓冲区组成。这些缓冲区按使用状况可以分为:空缓冲队列,装满输入数据的缓冲队列(输入队列),装满输出数据的缓冲队列(输出队列)。

另外,根据一个缓冲区在实际运算中扮演的功能不同,又设置了四种缓冲区:用于收容输入数据的工作缓冲区(hin),用于提取输入数据的工作缓冲区(sin),用于收容输出数据的工作缓冲区(hout),用于提取输出数据的工作缓冲区(sout)
在这里插入图片描述

总结

在这里插入图片描述

5.3.1 磁盘的结构

磁盘,磁道,扇区

在这里插入图片描述

如何在磁盘中读/写数据

在这里插入图片描述

盘面,柱面

在这里插入图片描述
可用(柱面号,盘面号,扇区号)来定位任意一个磁盘块。在文件的物理结构小节中,我们经常提到文件数据存放在外存中的几号块,这个快号就可以转换成(柱面号,盘面号,扇区号)的地址形式。
可根据该地址读取一个块

  1. 根据柱面号移动磁臂,让磁头指向指定柱面
  2. 激活指定盘面对应的磁头
  3. 磁盘旋转的过程中,指定的扇区会从磁头下面划过,这样就完成了对指定扇区的度/写

磁盘的分类

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

5.3.2 磁盘调度算法

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

  1. 寻找时间(寻道时间)Ts:在读/写数据前,将磁头移动到指定磁头所花的时间
    1. 启动磁头臂是需要时间的,假设耗时为s
    2. 移动磁头也是需要时间的。假设磁头匀速移动,每跨越一个磁道耗时为m,总共需要跨越n条磁道,则:寻道时间:Ts = s + m * n
  2. 延迟时间Tr:通过旋转磁盘,使磁头定位到目标扇区所需要的时间。设磁盘转速为r(单位:转/秒 或 转/分),则平均所需的延迟时间为Tr = (1 / 2) * (1 / r) = 1 / 2r
  3. 传输时间T:从磁盘读出或向磁盘写入数据所经历的时间,假设磁盘转速为r,此次读/写的字节数为b,每个磁道上的字节数为N,则传输时间T = (1 / r) * (b / N) = b / (rN)

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

先来先服务算法(FCFS)

根据进程请求访问磁盘的先后顺序进行调度。
在这里插入图片描述
优点:公平;如果请求访问的磁道比较集中的话,算法性能还算过得去
缺点:如果有大量进程竞争使用磁盘,请求访问的磁道很分散,则FCFS在性能上很差,寻道时间长

最短寻找时间优先(SSTF)

SSTF算法会优先处理的磁道是与当前磁头最近的磁道。可以保证每次的寻道时间最短,但是并不能保证总的寻道时间最短。(其实就是贪心算法的思想,只是选择眼前最优,但是总体未必最优)
在这里插入图片描述
优点:性能较好,平均寻道时间短
缺点:可能产生饥饿现象

扫描算法(SCAN)

SSTF算法会产生饥饿的原因在于:磁头有可能在一个小区域内来回来去的移动。为了防止这个问题,可以规定,只有磁头移动到最外侧磁道的时候才能往内移动,移动到最内存磁道的时候才能往外移动。这就是扫描算法的思想。由于磁头移动的方式像电梯,因此也叫电梯算法。

在这里插入图片描述
优点:性能较好,平均寻道时间较短,不会产生饥饿现象
缺点:

  1. 只有到达最边上的磁道时才能改变磁头移动方向,事实上,处理了184号磁道的访问请求之后就不再需要在往右移动磁头了
  2. SCAN算法对于各个位置磁道的响应频率不平均。(靠近边上的响应频率高)

LOOK调度算法

扫描算法(SCAN)中,只有达到最边上的磁道时才能改变磁头的移动方向,事实上,处理了184号磁道的访问请求之后就不需要再往右移动磁头了。LOOK调度算法就是为了解决这个问题,如果在磁头移动反向上已经没有别的请求,就可以立即改变磁头移动方向。(边移动边观察,因此叫LOOK)
在这里插入图片描述
优点:比起SCAN算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短。

循环扫描算法(C-SCAN)

SCAN算法对于各个位置磁道的响应频率不平均,而C-SCAN算法就是为了解决这个问题。规定只有磁头朝某个特定方向移动时才处理磁道访问请求,而返回时直接快速移动至起始端而不处理任何请求。
在这里插入图片描述

优点:比起SCAN来,对于各个位置磁道的响应频率很平均。
缺点:只有到达最边上的磁道时才能改变磁头移动方向,事实上,处理完184号磁道的访问请求之后就不需要再往右移动磁头了;并且,磁头返回时其实只需要返回到18号磁道即可,不需要返回到最边缘的磁道。另外,比起SCAN算法来,平均寻道时间更长。

C-LOOK调度算法

C-SCAN算法算法的主要缺点是只有到达最边上的磁道时才能改变磁头移动方向,并且磁头返回时不一定需要返回到最边缘的磁道上。C-LOOK算法啊就是为了解决这个问题。如果磁头移动的方向上已经没有磁道的访问请求了,就可以立即让磁头返回,并且磁头只需要返回到磁道访问请求的位置即可。
在这里插入图片描述
优点:比起C-SCAN算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短。

总结在这里插入图片描述

5.3.3 减少磁盘延迟时间的方法

在这里插入图片描述

减少延迟时间的方法:交替编号

若采用交替编号的策略,即让逻辑上相邻的扇区在物理上有一定的间隔,可以使读取连续的逻辑扇区所需要的延迟时间更小。
在这里插入图片描述

磁盘地址结构的设计

为什么磁盘的物理地址是(柱面号,盘面号,扇区号)而不是(盘面号,柱面号,扇区号)

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

若物理地址结构是(盘面号,柱面号,扇区号),且需要连续读取物理地址(00,000,000)~(00,001,111)的扇区:
(00,000,000)~(00,001,111)转两圈可读完
之后再读取物理地址相邻的区域,即(00,001,000)~(00,001,111),需要启动磁头臂,将磁头移动到下一个磁道。

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

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

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

5.3.4 磁盘的管理

磁盘初始化

磁盘初始化:

  1. 进行低级格式化(物理格式化),将磁盘的各个磁道划分为扇区。一个扇区通常可分为头,数据区域(如512B大小),尾三个部分组成。管理扇区所需要的各种数据结构一般存放在头,尾两个部分,包括扇区校验码(如奇偶校验,CRC循环冗余校验码等,校验码用于校验扇区中的数据是否发生错误)
  2. 将磁盘分区,每个分区由若干个柱面组成(即分为我们熟悉的C盘,D盘,E盘)
  3. 进行逻辑格式化,创建文件系统。包括创建文件系统的根目录,初始化存储空间管理所用的数据结构(如 位示图,空闲分区表)

引导块

计算机开机时需要进行一系列初始化的工作,这些初始化的工作是通过执行初始化程序(自举程序)完成的
初始化程序可以放在ROM(只读存储器)中。ROM中的数据在出厂时就写入了,并且以后不能修改。
注:ROM一般是出厂时就集成在主板上的。

初始化程序程序(自举程序)放在ROM中存在什么问题?
万一需要更新自举程序,将会很不方便,因为ROM中的数据无法更改。如何解决呢?

ROM中只存放很小的自举装入程序,完整的自举程序放在磁盘的启动块(即引导块/启动分区上),启动块位于磁盘的固定位置。

开机时计算机先运行“自举装入程序”,通过执行该程序就可找到引导块,并将完整的“自举程序”读入内存,完成初始化。
拥有启动分区的磁盘称为启动磁盘或系统磁盘(C:盘)

坏块的管理

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

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

对于复杂的磁盘,磁盘控制器(磁盘设备内部的一个硬件部件)会维护一个坏块链表。
在磁盘出厂前进行低级格式化(物理格式化)时就将坏块链进行初始化。
会保留一些“备用扇区”,用于替换坏块。这种方案称为扇区备用。且这种处理方式中,坏块对操作系统透明。

总结

在这里插入图片描述

固态硬盘SSD

固态硬盘的结构

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/364377.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果电脑插上移动硬盘没反应怎么回事 苹果笔记本移动硬盘无法写入 苹果电脑读取不到移动硬盘数据怎么办 移动硬盘连接苹果电脑无法读取的解决方案

通常情况下&#xff0c;当我们把硬盘接到苹果电脑上&#xff0c;我们是可以读取它的。但也有用户遇到过这种情况&#xff0c;就是苹果电脑无法正常读取硬盘&#xff0c;这是怎么造成的呢&#xff1f; 一、硬盘在苹果电脑上读取不出来的原因是什么&#xff1f; 硬盘在苹果电脑上…

Golang | Leetcode Golang题解之第198题打家劫舍

题目&#xff1a; 题解&#xff1a; func rob(nums []int) int {if len(nums) 0 {return 0}if len(nums) 1 {return nums[0]}first : nums[0]second : max(nums[0], nums[1])for i : 2; i < len(nums); i {first, second second, max(first nums[i], second)}return se…

FPGA SATA高速存储设计

今天来讲一篇如何在fpga上实现sata ip&#xff0c;然后利用sata ip实现读写sata 盘的目的&#xff0c;如果需要再速度和容量上增加&#xff0c;那么仅仅需要增加sata ip个数就能够实现增加sata盘&#xff0c;如果仅仅实现data的读写整体来说sata ip设计比较简单&#xff0c;下面…

T4打卡 学习笔记

所用环境 ● 语言环境&#xff1a;Python3.11 ● 编译器&#xff1a;jupyter notebook ● 深度学习框架&#xff1a;TensorFlow2.16.1 ● 显卡&#xff08;GPU&#xff09;&#xff1a;NVIDIA GeForce RTX 2070 设置GPU from tensorflow import keras from tensorflow.keras…

使用Vercel 搭建自己的Dashy导航页

背景 Dashy 是一个开源的自托管导航页面配置服务&#xff0c;它具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。用户可以利用 Dashy 将自己常用的一些网站聚合起来&#xff0c;形成一个个性化的导航页面。 同类的竞品还有Heimdall, Flare 等。 可以通过Docker 等…

selenium4如何指定chrome和firefox的驱动(driver)路径

pythonpytestselenium框架的自动化测试脚本。 原本用的chrome&#xff0c;很久没用了&#xff0c;今天执行&#xff0c;发现chrome偷偷升级&#xff0c;我的chromedriver版本不对了。。。鉴于访问chrome相关网站太艰难&#xff0c;决定弃用chrome&#xff0c;改用firefox。因为…

用易查分制作《假期安全承诺书》支持在线手写签名,一键导出打印

暑假将至&#xff0c;学校通常会下发假期安全承诺书让家长签署。 易查分可以实现网上下发安全承诺书通知&#xff0c;让学生家长进行签名确认&#xff0c;还可以导出PDF文件&#xff0c;方便打印一人一张的纸质版承诺书&#xff0c;下面就来教给大家如何使用吧&#xff01; 暑假…

【语言模型】Xinference的部署过程

一、引言 Xinference&#xff0c;也称为Xorbits Inference&#xff0c;是一个性能强大且功能全面的分布式推理框架&#xff0c;专为各种模型的推理而设计。无论是研究者、开发者还是数据科学家&#xff0c;都可以通过Xinference轻松部署自己的模型或内置的前沿开源模型。Xinfe…

第三十七篇——麦克斯韦的妖:为什么要保持系统的开放性?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 如果没有详细的学习这篇文章&#xff0c;我觉得我就是被麦克斯韦妖摆弄的…

[OtterCTF 2018]Graphic‘s For The Weak

恶意软件的图形中有些可疑之处。 软件图形 &#xff1f;&#xff1f;&#xff1f;这里的恶意文件都是 vmware-tray.ex使用procdump转存进程的可执行文件 &#xff08;可执行的&#xff09;导出了 &#xff0c;看文件里面是否存在 图片 volatility.exe -f .\OtterCTF.vmem --pro…

长鑫存储母公司斥资24亿美元发展国产HBM

国产DRAM厂商长鑫存储母公司睿力集成计划投资24亿美元在上海建一座高端封装工厂。据报道&#xff0c;该工厂将专注于高带宽存储器&#xff08;HBM&#xff09;芯片的封装&#xff0c;预计到2026年中开始投入生产。长鑫存储将利用来自多方投资者的资金进行建设&#xff0c;其中包…

CXL:拯救NVMe SSD缓存不足设计难题-2

LMB提出了基于CXL协议的内存扩展框架和内核模块。该方案利用CXL内存扩展器作为物理DRAM源&#xff0c;旨在提供一个统一的内存分配接口&#xff0c;使PCIe和CXL设备都能方便地访问扩展的内存资源。通过这个接口&#xff0c;NVMe驱动和CUDA的统一内存内核驱动可以直接高效地访问…

1-爬虫基础知识(6节课学会爬虫)

1-爬虫基础知识&#xff08;6节课学会爬虫&#xff09; 1.什么是爬虫2.爬取的数据去哪了3.需要的软件和环境4.浏览器的请求&#xff08;1&#xff09;Url&#xff08;2&#xff09;浏览器请求url地址&#xff08;3&#xff09;url地址对应的响应 5.认识HTTP/HTTPS5.1 http协议之…

如何应对UI测试自动化的不稳定循环!

以下为作者观点&#xff1a; 当我加入UI自动化团队时&#xff0c;我很高兴能为新功能的自动化测试用例开发做出贡献。然而&#xff0c;我很快意识到团队花费了大量时间来修复之前迭代中不稳定的测试。这种情况让我感到困惑&#xff0c;因为当自动化测试脚本已知不稳定时&#…

Excel+vue+java实现批量处理功能

需求背景: 产品创建流程比较复杂&#xff0c;有时候需要一次性创建多至10个&#xff0c;所以做了Excel维护产品信息&#xff0c;直接导入创建的功能。能极大提高效率。 简要概括实现&#xff1a; 一、参考单个创建&#xff0c;设计创建模板&#xff0c;表头对应填写字段名&…

《昇思25天学习打卡营第12天 | 昇思MindSpore基于MindSpore的GPT2文本摘要》

12天 本节学习了基于MindSpore的GPT2文本摘要。 1.数据集加载与处理 1.1.数据集加载 1.2.数据预处理 2.模型构建 2.1构建GPT2ForSummarization模型 2.2动态学习率 3.模型训练 4.模型推理

javaScript利用indexOf()查找字符串的某个字符出现的位置

1 创建字符串 2 利用indexof()查询字符串的字符 3 利用while循环判断indexOf是否等于-1&#xff0c;不等于-1就打印一次并且索引号1去查下一个字符 //创建字符串var str1234567812311231;var indexstr.indexOf(1);//查询该字符while(index !-1)//indexOf()没有查到会返回-1{…

【linux/shell案例实战】解决Linux和Windows的换行符CRLF和LF问题

目录 一.什么是Linux 和 Windows 的换行符 CRLF 和 LF 二.使用Linux 中命令 dos2unix 和 unix2dos 实现CRLF 和LF的转换 三.使用 windows 中的代码编辑器实现 CRLF 和 LF 的转换&#xff08;Notepad&#xff09; 一.什么是Linux 和 Windows 的换行符 CRLF 和 LF CR是Carria…

探索区块链:颠覆性技术的崛起

目录 一、引言 二、区块链技术概述 三、区块链应用场景 四、区块链面临的挑战 五、区块链的未来展望 六、结语 一、引言 在数字化浪潮的推动下&#xff0c;区块链技术以其独特的去中心化、透明性和不可篡改性等特性&#xff0c;正在逐步改变我们的生活。从金融领域到供应…

vue组件全局注册

描述&#xff1a; vue组件的注册分为局部和全局注册两部分&#xff0c;局部注册相对容易&#xff0c;不做赘述&#xff1b;而不同框架的注册方法又有所不同&#xff0c;下面针对vite框架和vue-cli框架的注册分别进行说明 vue组件全局注册 一、vite框架中全局组件注册二、Vue-cl…