操作系统

前言

本篇文章的内容结合了哈工大李治军老师操作系统课程,王道考研操作系统的资料以及学习了B站CodeSheep的一次知识梳理,并且为了便于理解学习,增加了个人的一些解释。总之,概括而言对于开发人员来说,操作系统需要下四个方面进行学习:进程/线程;并发/锁;内存管理与调度;I/O原理,本文也将围绕这几点逐渐深入。

一、常用术语总结

名词 概念
PCB 进程控制块(PCB Process Control Block),系统中存放、管理和控制进程信息的数据结构称为
TCB 线程控制块
FCB 文件控制块
PID 进程ID(Process ID)
PSW 程序状态字寄存器,用于存放PC、IR等的信息
PC 程序计数器,存放下一条指令地址
IR 指令寄存器,存放到当前进行的指令
半双工 半双工和全双工是计算机网络中的概念,意思是通讯同一时间只允许一方发送数据(对讲机)
全双工 通信允许两方向上同时传输数据(电话)
P操作 来自荷兰语proveren,代表wait原语,通常使用P(S)代替wait(S)
V操作 来自荷兰语verhogen,代表原语signal,通常使用V(S)代替signal(S)
用户态 一般的操作系统对执行权限进行分级,分别为用保护态和内核态。用户态相较于内核态有较低的执行权限,很多操作是不被操作系统允许的,从而保证操作系统和计算机的安全。
内核态 内核态相当于一个介于硬件与应用之间的层,可以进行硬件的调度、使用,可以执行任何cpu指令,也可以引用任何内存地址,包括外围设备, 例如硬盘, 网卡,权限等级最高。
用户态内核态切换 三种情况下,用户态会转换到内核态,系统调用、程序异常(例如/0,内存资源耗尽等)、来自外围设备的中断
系统调用/程序接口 用户程序通过系统调用的方式才能对硬件进行使用,或者说操作系统将使用硬件的接口提供给用户程序
中断 中断是操作系统内核程序夺取cpu的唯一途径,或者说用户程序调用内核代码的唯一途径,因为在一般情况下,操作系统会将cpu使用权交给应用程序。

二、进程、线程

在进程、线程这一章节除了会讲进程、线程的概念,也会穿插,并发,锁。

2.1 进程

进程由PCB(进程控制块)组成,包含了PID、资源分配情况、进程运行情况。

对用户而言,我们能看到一个个PID,而对操作系统而言,底层需要处理的是一个个PCB

下图是通过任务管理器的用户视角下的进程。

2.1.1 进程控制

进程控制相关的原语:创建、终止、阻塞、唤醒、切换。也就是说我们通过原语进行进程控制,原语的执行具有原子性,不允许被中断,原语的实现可以通过“关中断指令”和“开中断指令”实现。

进程状态:运行态,就绪态,阻塞态

进程状态转换的条件:

运行 -> 阻塞 等待I/O或事件完成

运行 -> 就绪 进程的CPU时间片用完

就绪 -> 运行 获得了CPU的时间片

阻塞 -> 就绪 I/O或事件完成

下图为进程控制的流程图。

2.1.2 进程的组织形式

在一个系统中,通常有数十、数百乃至数千个PCB。为了能对他们加以有效的管理,应该用适当的方式把这些PCB组织起来。

进程的组织形式分为两种:链接式和索引式

根据进程状态的不同,创建不同的索引表,可以通过指针可以通过索引表指到个PCB。

2.1.3 程序的执行

程序的状态字寄存器 PSW用来存放两类信息:一类是体现当前指令执行结果的各种状态信息,如有无进位(CY位),有无溢出(OV位)等;另一类是存放控制信息,如允许中断(IF位),跟踪标志(TF位)等。

相较于程序,进程是动态的而程序是静态的

2.1.4 进程通信

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

进程通信方法:共享存储、信号量、消息队列/信箱、管道通信、套接字(这个在计算机网络有涉及相关知识,可以把套接字理解为一个窗口)

共享存储

消息传递

通过原语控制,进程1发送消息到消息缓冲队列或者信箱中,进程2从消息队列或者信箱中接收消息。

管道通信

2.2 线程

进程是资源分配的基本单位,线程是调度的基本单位,往往一个进程包含多个线程。线程并发,系统开销小,不需要切换系统资源。

线程可以分为用户级线程和内核级线程,早期如Unix只支持进程,不支持线程,所以当时的线程是由"线程库"实现的,用户将进程分为多个线程,放入线程库,但操作系统仍然是按照进程进行处理的。

这种用户级线程是由程序负责管理的,包括进行切换。这种切换方式开销小,效率高,但下图当一个用户级线程被阻塞后,整个进程都将会被阻塞

多线程模型

内核级线程是由操作系统完成调度的。

将n个用户级线程映射到m个内核级线程上( n >= m),优点是克服了多对一模型并发度不高的缺点,又克服了一对一模型中一个用户进程占用太多内
核级线程,开销太大的缺点。

2.3 进程调度

2.3.1 三种调度方式

调度的产生是因为系统资源有限,没办法同时处理所有进程,需要特定的规则分配执行顺序,从而有了调度

操作系统调度层次分为三类:高级调度、中级调度、低级调度。

高级调度:从外存的后备作业中挑选一个(多个),建立相应的PCB,获得竞争处理的权力。

后面会讲到的虚拟内存技术出现后,为了提高系统的利用率和吞吐量,会将暂时等待的进程挂起到外存。

中级调度:能够决定哪个被挂起的进程重新回到内存中。

低级调度:从就绪队列中选取一个进程,使其能够被CPU处理。

三种调度方式的频率从低到高。

进程调度时机:当前运行进程主动放弃(进程中止、异常、主动请求阻塞),被动放弃(时间片用完、更高优先级的进程进入就绪队列等)

2.3.2 调度算法评价指标

作为开发人员的话,大致了解以下即可,毕竟工作中几乎不会涉及到具体指标计算

CPU利用率 = 忙碌的时间/总时间

系统吞吐量 = 总共完成了多少道作业/总共花了多少时间 (简单理解就是一个完成作业的速度指标)

周转时间= 作业完成时间– 作业提交时间

平均周转时间 = 各作业周转时间之和/作业数

带权周转时间 = (作业完成时间– 作业提交时间)/作业实际运行的时间,这项指标一定是大于等于1的,越接近一则越好

平均带权周转时间 = 各作业带权周转时间之和/作业数

等待时间,指进程/作业处于等待处理机状态时间之和

响应时间,指从用户提交请求到首次产生响应所用的时间。例如键盘事件响应时间,鼠标点击响应时间

2.3.3 【重点】调度算法

先来先服务FCFS:顾名思义,先来的进程先服务,主要从“公平”的角度考虑(类似于我们生活中排队买东西的例子),非抢占式算法。

短作业优先SJF:最短的作业/进程优先得到服务,追求最少的平均等待时间,非抢占式算法。

最短剩余时间优先算法SRTN:每当有进程加入就绪队列改变时就需要调度,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机,当前运行进程重新回到就绪队列。是一种抢占式算法。

根据图示要区分最短剩余时间优先算法和短作业优先算法。

高响应比优先HRRN,相应比 = (等待时间+要求服务时间)/要求服务时间

,是一种非抢占式的调度算法,只有当前运行的进程主动放弃CPU时(正常/异常完成,或主动阻塞),才需要进行调度。

以上方法适用于早期的批到处理系统,适用于交互式系统的调度算法。

适用于目前交互式系统的调度算法,在交互式操作系统中,可以将任务划分为前台任务(鼠标、键盘等任务)和后台任务,前台任务更关心响应事件,后台任务更关心周转。

时间片轮转调度算法RR:周期性切换PCB,各个PCB轮流使用CPU

最高优先级调度算法即前台进程优先级高于后台进程,系统进程优先级会高于用户进程,特点就是不公平,容易产生饥饿。

1973年关闭的MIT的IBM 7094时,发现有一个进程在1967年提交但一直未运行

2.4 实现进程互斥、同步、前驱

如果要清晰讲述需要了解代码逻辑,对于非专业人员来说,必要性不大,这里就不详细罗列代码了。

2.4.1 硬件实现进程互斥

进程互斥:当一个进程进入临界区后,另一个进程必须等待。

硬件能够实现进程互斥,有三种方式:利用“开/关中断指令”实现TSL指令SWAP指令

2.4.2 信号量机制实现互斥、同步、前驱

信号量机制:用户进程可以通过使用操作系统提供的原语对信号量进行操作,从而很方便的实现进程的互斥、同步、前驱。

不要一头钻到代码里,要注意理解信号量背后的含义,一个信号量对应一种资源
信,在操作系统中,信号量在源码中其实就对应着一个变量,代表着某种资源的数量,通过信号量可以实现进程互斥、同步、前驱。

进程同步的理解:要让各并发进程按要求有序地推进。若PCB2 的“代码4”要基于PCB1 的“代码1”和“代码2”的运行结果才能执行,那么我们就必须保证“代码4”一定是在“代码2”之后才会执行。

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

信号量保护:共享数据在没有保护的情况下,会出现安全问题,所以需要锁来进行保护,锁本质也是一个变量,用来保护信号量安全,那锁本身的安全谁来保护?我们不能在这里套娃对不对,所以锁是一种硬件原子指令,当要进入临界区时,上锁,离开临界区时解锁。下面的知识有一些扩展了。

在cpu芯片上有一个HLOCK Pin,可以通过发送指令来操作,将#HLOCK Pin电位拉低,并持续到这条指令执行完毕,从而将总线锁住,这样同一总线上的其他CPU就不能通过总线来访问内存了。最开始这些功能是用来测试cpu的,后来被操作系统实现而封装成各种功能:关键代码段,信号量等。

作者:tracy_668
链接:https://www.jianshu.com/p/61490effab35
来源:简书

2.5 死锁的概念与处理

死锁的4个条件,缺一不可

  • 互斥条件:对必须互斥使用的资源的争抢才会导致死锁

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

  • 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己有的资源保持不放。就像很窄的桥,两个人都要去对面,但谁又都无法让出位置来

  • 循环等待条件:存在一种进程资源的循环等待,链中的每一个进程已获得的资源同时被下一个进程所请求。想象有一个闭环,闭环上每个人都需要下一个人手上的某个资源,那么所有人都没办法满足

    下图就像我们的一个死锁

死锁的处理方式

  • 死锁预防

    • 破坏互斥条件(创建一个队列,所有的请求都会被快速响应,然后队列逐渐将请求发送到处理器进行整理)

    • 破坏不剥夺条件(进程的某个资源得不到满足时,就必须立刻释放所持有的资源)

    • 破坏请求和保持条件(静态分配,进程在运行前就一次性申请全部的资源,不满足就不让允许,就像过桥时保证桥上没人才让通行,否则禁止通行)

    • 破坏循环等待条件(资源编号,进程必须按照编号递增的顺序请求资源,这样就不会出现持有大资源请求小资源的情况,也就不会有循环的等待)

      (方式较多,这里简单列举一些案例)

  • 死锁避免

银行家算法:进程提出资源申请时,先判断这次分配会不会导致系统进入不安全状态,如果会则不答应请求,让该进程阻塞。简而言之,请求不能大于手中的资源。这种算法也叫银行家算法。

  • 死锁检测与恢复

    检测方法通过死锁检测算法,下面以图的方式说明


能够消除所有边,就不会发生死锁如下图


不能消除所有边就会发生死锁

**死锁恢复:**资源剥夺将死锁的进程挂起,释放资源;撤销进程,直接将部分或者全部死锁进程撤销;进程回退,让进程回退的足以避免死锁的地方。

  • 死锁忽略

    顾名思义,忽略这个死锁,死锁概率本不高,就算出现了也只是局部的死锁,直接不管反而能提高资源利用率与整体运行的速度,也有个好听的名字叫鸵鸟算法,这样性能会提升不少,大部分操作系统也采用死锁忽略的策略。

三、内存

内存:程序执行前要先放到内存中才能被CPU处理。计算机小白可能以为内存就是存储空间,其实不然。

地址:4G的内存空间,有4*230个字节,也就是232个字节,要表示全部的字节就需要32位的二进制地址,这也就是我们以前流行的32位操作系统的由来。但目前内存基本上都是8G,16G,所以32位已经不能满足需求,当前主流是64位操作系统,能表示2^64个字节,最高4,294,967,296G的内存空间,远远满足当前的任何个人电脑地址表达需求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MUoaImAi-1606404338305)(操作系统.assets/image-20200925082639253.png)]

3.1 程序装入内存

可执行文件需要放在内存中才可以运行,程序中的指令是逻辑地址,而内存中的地址是物理地址。如何将逻辑地址转为物理地址?

  1. 绝对装入

下图为可执行文件指令。

假如0-100的地址已经被占用,系统知道装入模块要从地址为100 的地方开始存放,编译时就将指令的绝对地址载入了可执行文件,即

  1. 静态重定位

编译、链接后的装入模块的地址都是从0开始的,即可执行文件指令地址不变,在装入内存时,逻辑地址全部+100,装入内存中。所以作业一旦装入就没办法再更改、申请内存空间。

  1. 动态重定位

又称动态运行时装入。编译、链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行

这种方式需要一个重定位寄存器的支持,寄存器记录了初始进入的的地址即100,在程序运行时,会动态的将指令中的逻辑地址增加上初始地址。

3.2 链接方式

  1. 静态链接

在程序运行之前,先将各目标模块及它们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。

  1. 装入时动态链接

装入时动态链接:将各目标模块装入内存时,边装入边链接的链接方式。

  1. 运行时动态链接

在程序执行中需要该目标模块时,才对它进行链接。其优点是物理地址便于修改和更新,便于实现对目标模块的共享。

3.3 内存管理

操作系统需要负责内存空间的分配与回收、内存空间扩充、地址转换、内存保护。

  1. 分配与回收

分配在程序链接方式已经讲明白了,回收即对内存中的进程进行撤销、挂起等操作。

  1. 扩充

这会涉及到后面的虚拟内存技术,这也十分常见,比方说我们5G的程序如何运行在2G的内存上,这就需要扩充。

  1. 地址转换

在装入内存已经讲过。

  1. 内存保护

简单来说就是操作系统保护已经在内存上的进程不被干扰。一种方式是设置上下限寄存器存放进程上下界,如100-179被占用,其他进程不可使用这里的内存。另外一种方式是重定位寄存器与界地址寄存器,如下图

通过逻辑判断内存是否能执行某操作。

3.4 覆盖技术与交换技术

技术产生的原因:程序所需的运行空间大于实际内存大小,需要让内存发挥出更大的作用。

覆盖技术:按照逻辑,将不可能同时被访问的程序段共享一个覆盖区

交换技术:内存紧张时,将部分进程暂时挂起(放置到外村),将外村已具备运行条件的进程换入内存。

3.5 连续分配管理方式

单一连续分配:用于早期操作系统,内存被划分为系统区和用户区,内存只能有一道用户程序,局限性不言而喻。

固定分区分配:整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。

动态分区分配:不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区。

动态分区分配会产生外部碎片,外部碎片,是指内存中的某些空闲分区由于太小而难以利用。

3.6 动态分区分配算法

  • 首次适应算法

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

  • 最佳适应算法

因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。

  • 最坏适应算法

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

  • 邻近适应算法

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

综合来看

3.7 基本分页存储管理

在3.6中的算法总是存在种种问题,在实际操作系统中,分页可以解决内存分区导致的效率、碎片问题。

图示

页框: 每个分区就是一个“页框”(页框=页帧=内存块=物理块=物理页面)

页面:将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面”

页框不能太大,否则可能产生过大的内部碎片导致浪费。

页框和页面总是记混,技巧其实很简单只要记住页面放在页框中,就再也不会记混了。

页表:操作系统要为每个进程建立一张页表。页表通常存在PCB,这里概念不清的话可能会有疑惑为什么PCB中会有页表,仔细阅读前面的部分,PCB中不光存放进程,还存放着进程信息、PID、IO情况等多个内容。

页表记录进程页面和实际存放的内存块之间的映射关系

页表项所占字节:假设某系统物理内存大小为4GB,页面大小为4KB,则有2^32 / 2^12 = 2^20 个内存块,那么每一个块号就需要20bit,至少3字节来表示。由于页号是隐含的,因此每个页表项占3B。

同样的,有进程和内存,就有地址转换的问题进程的页号是逻辑地址,内存的页框号是物理地址,中间需要计算页内偏移量。

  • 页号= 逻辑地址/ 页面长度(取除法的整数部分)
  • 页内偏移量= 逻辑地址% 页面长度(取除法的余数部分)

逻辑地址A 对应的物理地址= P号页面在内存中的起始地址+页内偏移量W

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

快表TLB:又称联想寄存器,是访问速度比内存快很多的高速缓存。

快表为什么速度快:直接从快表中取出该页对应的内存块号,再将内存块号与页内偏移量拼接形成物理地址最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅需一次访存即可。

慢表则要在多级页表中找到对应的页表,再从相应的页号中取出内存块号。

就像看一本书,快表放了书签,而慢表则要慢慢找上次看到了哪

局部性原理:

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

3.9 两级页表

为什么要有两级页表

根据局部性原理,进程某个时间段内只需要访问几个页面就可以正常运行了,没必要让整个页面都在内存中常驻。同时,过大的页表还会占用很多页框,也就是内存空间。

示意图:

当整个页表被分为多个页表,在内存中只需要放入有需求的页表,从而提高效率,节省空间。

3.10 基本分段管理

分段管理:以段为单位进行分配,每个段在内存中占据连续空间,各段之间可以不相邻。大体上与分页类似,与“分页”最大的区别就是——离散分配时所分配地址空间的基本单位不同。

3.11 虚拟内存

在真实的操作系统中,通常采用段页式存储管理,段面向用户,页面向硬件。

虚拟内存解决的问题:

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

虚拟内存的实现:

  • 基于局部性原理,在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行。
  • 在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。
  • 若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。在操作系统的管理下,在用户看来似乎有一个比实际内存大得多的内存,这就是虚拟内存

3.12 请求分页管理

请求分页管理:

在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存

缺页中断: 在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。

缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项。如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,同时要注意,若某个页面被换出外存,则快表中的相应表项也要删除,否则可能访问错误的页面

理解缺页,缺页就像货架上缺少了商品,需要从仓库里调取商品,就先暂停这个货架的销售,等商品调取完毕再重新出售。

3.13 页面置换算法

置换算法的评价指标是:缺页的次数,某种算法让缺页次数最低,调度效率最高,那就是最优的算法

  1. 最佳置换算法

每次淘汰的页面都是以后永久不用或最长时间不使用的页面,保证最低的缺页率。显然,这种需要预测未来的算法不可能实现。

  1. 先进先出算法FIFO

缺页时,淘汰最早进入的页面。算法简单,但局限性也明显,例如某些经常使用的页面一直被换进换出,和使用频率低的页面有相同的被换出的机会。

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

每次淘汰的页面都是最近最久未使用的页面。需要在页面中添加一个记录项,记录上次被访问以来经历的时间t,当需要淘汰页面时,选择时间t最大的淘汰,也就是最久未使用的淘汰。算法设计虽好,但开销很大,实现困难。

  1. 时钟置换算法

时钟置换算法也可以称为最近未使用算法。是一种性能和开销均衡的算法。

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

如下图。

了解即可

问题:缺页很少,访问位都是一,那么扫描了一轮进行第二次扫描,就相当于FIFO算法,为了改进这种情况,提出了下面的算法。

改进版的时钟算法(有很多改进方式,这里只是一种):如果把页面看成钟表,原来的慢指针相当于时针,现在添加一个快指针,相当于分针,分针扫描要比时针快,如果一个页面在一定时间限制内没有访问,就设访问位为0,缺页时直接换出。

四、I/O原理

注意文件索引和文件目录结构的区别,索引是检索文件的方式,而文件目录结构是用户管理计算机文件的一种结构,单级目录、多级目录等等。在用户目录的基础上,文件控制块FCB会指向对应的索引块。

4.1 文件的逻辑结构 【了解即可】

文件可以分为两类:

  1. 无结构文件

文件内部数据就是一系列二进制流或字符流。最典型的就是txt文件。

  1. 有结构文件

由一组相似的记录组成,又称记录式文件。典型的excel表、数据库表等。

有结构文件的逻辑结构又分顺序文件索引文件索引顺序文件,注意逻辑结构是展示给用户的,是文件的组织形式,例如是一张顺序存储的excel表格,还是一张excel索引表加上excel顺序表,还是多级索引加顺序,而不是在计算机上的存储方式。

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

顺序存储即逻辑相邻的文件物理上也相邻,链式存储即在末尾添加新的文件。

记录的类型又分为可变长和不可变长记录:

问题:对于可变长记录文件,要找到第i 个记录,必须先顺序第查找前 i - 1 个记录,但是很多应用场景中又必须使用可变长记录。如何解决这个问题?

之后提出了索引文件:简单而言就是引入了索引表的文件。索引表本身是顺序文件,即索引表顺序存储在一起。

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

索引顺序文件:索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是:并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项,索引表项的地址直接指向顺序文件所在区域,再顺序查找到所需的文件,从而节省了很大的空间。(例如我们可以通过An Qi找到An Kang、An Jie等,而不用在索引表中存放这么多信息。另外索引项之间不需要有按照逻辑关系排列)

多级索引顺序文件:在索引顺序文件的基础上再增加层次深度,可以减少查找的次数(顺序查找范围缩小了)

4.2 文件目录

文件目录可以分为:单级目录结构两级目录结构多级目录结构(树形目录结构)

单极目录结构:顾名思义,所有的文件放在一个目录中,类似于一个仓库把所有文件不加整理的堆放在一起,显然效率会很低下。

两级目录结构:主要分为主文件目录和用户文件目录。类似于仓库中加了几个员工货架,不同员工的货物放在不同货架,但在一个货架中文件还是采用堆砌式的存储。

多级目录结构,又称树形目录结构:我们当前主流操作系统都是多级目录结构,简而言之就是文件目录可以一级一级的延申,从而文件更有条理。

FCB(文件控制块),首先来看一张图,如果文件目录都以这种表的形式进行信息查找,会大大降低运行效率,增加系统负担。

提出对策,其实在查找各级目录的过程中,只需要用到文件名这个信息,可以考虑让目录表瘦身来提升效率。

索引结点指针指向索引结点(文件名之外的其他信息就存放在结点中,从而按需读取,提升效率)

FCB

每一个文件都有一个FCB,记录了文件的地址、信息、权限等等属性

4.3 文件的物理结构【重要】

最重要的三种物理结构:顺序、链接、索引,其中最主要使用的是索引文件,可以随机访问,同时增删效率高。

思考:想想数据结构中,顺序表和链表分别的优缺点是什么?

文件的物理结构是文件分配在计算机存储上的分配方式。分配的基本单位是 物理块,可以构想一下,一个大文件,如一首音乐23MB,难道直接一整个塞入硬盘吗?显然可能会出现一些问题,硬盘的空间也需要不断调整,就像内存分页一样,硬盘也被分为小的物理块号方便进行调度。

  • 连续分配

优点:支持顺序访问和直接访问(即随机访问);连续分配的文件在顺序访问时速度最快
缺点:不方便文件拓展;存储空间利用率低,会产生磁盘碎片

  • 链式分配

    隐式

采用链式分配(隐式链接)方式的文件,只支持顺序访问,不支持随机访问,查找效率低。另外,指向下一个盘块的指针也需要耗费少量的存储空间。

显式

直观理解就是在隐式的基础上添加了一张表,从表上能看出不同物理块号的下一块的地址

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

  • 索引分配

    • 单级
    • 多级

    索引就是文件分成不同的物理块存入磁盘,对每个物理块都有一个索引与之对应,需要读写时就通过索引表查询其物理地址进行相关操作。

4.3 磁盘结构

磁道:每一圈就是一个磁道,最内侧磁道面积最小,所以数据密度最大

扇区:磁道被划分为小的磁盘块

一个盘片可能有两个盘面;每个盘面对应一个磁头;所有磁头连在一起,共进退;每个盘面的相对位置的磁道组成柱面

两种类型的磁盘:

4.4 磁盘调度算法

磁盘调度算法要解决的核心问题就是寻道时间,即移动磁头的时间,而其他的启动时间、传输时间都很迅速,不是最主要的时间消耗。

这里讲三种算法:

  1. 先来先服务FCFS

根据进程请求房屋内磁盘的现后顺序进行调度。符合惯性思维,但在很多时候,效果很差。

  1. 最短寻找时间优先(学过数据结构与算法的话,核心思想就是贪心算法),该算法会优先处理与当前磁头最近的磁道的需求。

那么很可能磁头就会如图所示的移动,也会存在饥饿问题:磁头只在一个小区域移动,而不能满足需要远距离移动的需求。例如不断有18->38,38->18的需求,那磁头就不会执行18->150的请求,从而产生饥饿。

  1. 扫描算法

核心思想,只有磁头移动到最外侧磁道的时候才能往内侧移动,移动到最内侧的时候才能向外侧移动。

这样就不会产生饥饿问题。

4.5 文件共享

文件共享分两种链接方式,硬链接和软连接

硬链接就是在另一个用户的目录中,索引结点指针直接指向了发送分享的用户的索引节点,从而实现了共享,count的数量代表文件正在被几个用户使用。

软连接,类似于快捷方式,记录了原文件的路径,然后层层查找。

例如文件2的内容是 C:/User1/aaa,也就是要去User1中寻找aaa的文件名对应的索引结点。

4.6 文件保护

文件保护有三种方式口令、加密、访问控制

  1. 口令

为文件设置一串口令,就像打开手机需要先解锁。

  1. 加密

使用加密方法对文件加密,只有拥有正确的解密方法才能解密,有点像不同军队之间进行通信,要实现进行加密,要是想窥探敌情,就要对密文进行破解。

  1. 访问控制

每个文件的FCB或者索引结点中设置访问控制表,如windows中,设置了很多的访问权限,例如

4.7 I/O设备

I/O就是输入输出,I/O设备就是可以将数据输入到计算机或将计算机数据输出的设备,常见的:鼠标、键盘、音响、显示器、打印机、话筒、摄像头等等。

I/O控制器:CPU无法直接控制I/O设备,需要一个电子部件去充当中间人,这个部件就是I/O控制器,CPU控制I/O控制器,I/O控制器控制I/O设备。

假如我们的CPU能够控制I/O设备,那不同的厂商、不同型号的设备,都要对应进行编码,显然是不切实际的,所以CPU要采用通用调度方式调度I/O设备从而需要I/O控制器。

I/O控制器的组成

以下作为了解。

例如我们在Java语言中,调用System.out.Println(),这本身并不能在显示器上打印,而需要通过操作系统调用write方法,接着调用字符设备接口,命令显示器写。

王道 操作系统听课笔记整理相关推荐

  1. 王道操作系统考研笔记——2.1.6 处理机调度的概念和层次

    文章目录 2.1.6 处理机调度的概念和层次 2.1.6.1 调度的基本概念 2.1.6.2 高级调度 2.1.6.3 中级调度 2.1.6.4 进程的挂起态和七状态模型 2.1.6.5 低级调度 2 ...

  2. 王道操作系统考研笔记——2.3.4 信号量机制

    文章目录 2.3.4 信号量机制 2.3.4.1 引入 2.3.4.2 整型信号量 2.3.4.3 记录型信号量 2.3.4.4 小结 2.3.4 信号量机制 知识总览 在1965年,荷兰学着Dijk ...

  3. 王道操作系统考研笔记——2.3.3 进程互斥的硬件实现方法

    文章目录 2.3.3 进程互斥的硬件实现方法 2.3.3.1 中断屏蔽方法 2.3.3.2 TestAndSet指令 2.3.3.3 Swap指令 2.3.3.4 小结 2.3.3 进程互斥的硬件实现 ...

  4. 王道操作系统考研笔记——2.2.0 交互式系统调度算法

    2.2.0 交互式系统调度算法 知识总览 2.2.0.1 时间片轮转 知识点 说明 英文名 RR,Round-Robin 算法思想 公平地.轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响 ...

  5. 王道操作系统考研笔记——2.1.8 调度算法的评价指标

    文章目录 2.1.8 调度算法的评价指标 2.1.8.1 CPU利用率 2.1.8.2 系统吞吐量 2.1.8.3 周转时间 2.1.8.4 等待时间 2.1.8.5 响应时间 2.1.8.6 小结 ...

  6. 王道操作系统考研笔记——2.1.7 进程调度的时机、切换与过程、方式

    文章目录 2.1.7 进程调度的时机.切换与过程.方式 2.1.7.1 进程调度的时机 2.1.7.2 进程调度的方式 2.1.7.3 进程的切换和过程 2.1.7.4 小结 2.1.7 进程调度的时 ...

  7. 王道操作系统考研笔记——2.1.5 线程概念与多线程模型

    文章目录 2.1.5 线程概念与多线程模型 2.1.5.1 线程的来源 2.1.5.2 线程机制带来的变化 2.1.5.3 线程的属性 2.1.5.4 线程的实现方式 2.1.5.5 多线程模型 2. ...

  8. 王道操作系统考研笔记——1.1.6 系统调用

    如果这篇博客对您有用的话,可以给我点个赞吗,这对我很重要,谢谢!❤️ 文章目录 1.1.6 系统调用 1.1.6.1 系统调用和作用 1.1.6.2 系统调用和库函数 1.1.6.3 系统调用背后的过 ...

  9. 王道操作系统考研笔记——1.1.2 操作系统的特征

    如果这篇博客对您有用的话,可以给我点个赞吗,这对我很重要,谢谢!❤️ 1.1.2 操作系统的特征 文章目录 1.1.2 操作系统的特征 1.1.2.1 并发 1.1.2.2 共享 1.1.2.3 并发 ...

最新文章

  1. struts2请求处理过程源代码分析(1)
  2. SAP S/4 HANA新变化-主数据:物料主数据
  3. mysql latid1_【转】mysql触发器的实战经验(触发器执行失败,sql会回滚吗) | 学步园...
  4. 牛客华为机试第3题python
  5. pptp client
  6. 使用docker-compose部署sentinel
  7. 常见的社会潜规则有哪些?
  8. 【MATLAB统计分析与应用100例】案例014:matlab读取Excel数据,调用stepwise函数作交互式逐步回归分析
  9. php---自动生成flash图表(包括你想要的其他类型的图表)
  10. linux挑战:历史命令_博客挑战:分享您关于社区运作方式的知识
  11. java socket 读不到数据_Java Socket通信以及可能出现的问题解决
  12. python爬虫课程大纲_马哥2018python全栈+爬虫+高端自动化课程大纲
  13. Chrome插件:云音乐听歌识曲
  14. signature=b4b1c7e18770785c0aa672d85aa24d2b,Surveying Extended GMSB Models with mh=125 GeV
  15. 实施经理的工具箱--走出软件作坊:三五个人十来条枪 如何成为开发正规军(五)
  16. GLSL 实现 FXAA 后处理效果
  17. TIA博途中如何通过PLC变量控制开始和停止记录数据?
  18. K8SPod详解之pod配置
  19. 快速有效查找和下载美国专利
  20. paper to do

热门文章

  1. 目标分割:Mask RCNN
  2. android 的函数调用,安卓版在函数内部调用子程序,子程序如何能得到函数过程中得到的变量 _ 按键精灵手机版 - 按键精灵论坛...
  3. 怎么把word转换成excel表格的格式
  4. Ofd文档要修改怎么办?可以转成Word吗
  5. URL地址中的中文乱码问题的解决
  6. ssm保险办理系统毕业设计源码012232
  7. word简单三线表制作(分列、分行)
  8. 管理信息化涉及的领域
  9. 柴达木盆地第四大气区探实 尖北产量超亿方
  10. EtherCAT总线运动控制器应用进阶一