操作系统(下)

277 阅读1小时+

文件逻辑结构

文件分为无结构文件和有结构文件,其中后者可以继续细分为顺序文件、索引文件以及索引顺序文件

image-20230819014208159

污垢结构文件就是一系列的字符流,没有明显的结构特征,因此我们不做探讨

image-20230819014234347

在有结构文件中,每条都有一个关键字,比如下图中的学号,其实就是唯一ID,这个搞过数据表的应该是懂的都懂了

image-20230819014325204

有结构文件可以继续细分为定长记录和可变长记录,现实中的记录基本都是后者

image-20230819014412882

比如说下面的记录就是可变长记录,这些记录总是有数据项是不确定长度的,爱多长多长

image-20230819014517582

顺序文件指的是文件中的记录在逻辑上一个连续排列的,各个记录在物理上可以说是顺序记录,也可以是链式存储,前者在逻辑上相邻的记录在物理上也相邻,而后者则不一定,同时顺序文件还可以继续细分为串结构和顺序结构,前者指的是记录之间的顺序与关键字无关(此时同样按照记录存入的时间来排序),后者则是记录之间的顺序按照关键字排序

image-20230819014816751

只有顺序文件顺序存储且为定长记录时才可能实现随机存取,当其为串结构时无法快速找到某关键字对于的记录,而采用顺序结构时则可以,这里为什么不可以其实是有说明的,但是我属实是没整明白他在讲什么,所以还是等到上课的时候问老师吧

一般来说顺序文件指的就是物理上顺序存储的顺序文件,其缺点是增加/删除一个记录比较困难(如果是串结构则比较简单)

image-20230819015327163

对于可变长记录我们用索引表实现快速查找,索引表本身是定长记录的顺序文件,其可以保存对逻辑文件的指针,这样操作系统可以通过索引号实现快速查找,其一般用于要求对信息处理及时性比较高的场合,同时也可以对记录中不同的数据项建立多个索引表

其实这个就跟Mysql里的索引概念差不多,很好理解的不多谈了

image-20230819015724108

如果给每个记录都建立一个索引,那么可能会造成索引表很大,为此可以给记录分组,然后每个索引表里的索引项都对于一个分组,这个方式就解决上述问题

image-20230819020123937

同时使用该方法的效率也不会很差,这个思想其实就是用空间换时间,这一般是值得的,因为时间就是金钱,而空间往往很不值钱

image-20230819020336839

有时候即使建立索引表效率还是不足,此时可以建立多级索引表,给索引表建立索引表,这样可以进一步缓解效率问题

image-20230819020537523

最后我们来看看文件的逻辑结构的总结

image-20230819020610096

有结构文件的总结

image-20230819020638530

文件目录

实现文件目录的关键数据结构是文件控制块,而文件目录就是我们非常熟悉的Windows下的文件夹

image-20230819024325198

目录本身是一种文件结构,由一条条记录组成,每条记录有文件名、类型、存取权限、物理地址等内容组成

image-20230819024749028

目录文件中的每一条记录就是一个文件控制块FCB,其包含的文件的基本信息,但是最重要和最基本的内容还是文件名和文件存放的物理地址

image-20230819025140881

一般来说,我们需要对目录进行搜索和CURD等操作

image-20230819025415933

早期的操作系统并不支持多级目录采用单级目录结构,这种结构不适合于多用户操作系统

image-20230819025646458

后续采用二级操作系统来解决多用户操作的问题,两级目录结构指的是目录分为主文件目录和用户文件目录,主文件目录指出属于哪个用户的目录,而用户文件目录就是用户的目录,这种方式仍然存在用户不能对自己的文件进行分类的问题

image-20230819025759581

多级目录结构又称树形目录结构,这种结构就很类似于我们现在的目录结构了,根目录下有多个目录,每个目录下都可以有目录和文件,可以无限嵌套,此时从根目录触发的路径是绝对路径

image-20230819030013341

如果每次都打开一个文件都从绝对目录中找,效率太低,因此出现了当前目录的概念,操作系统对于当前的目录可以使用相对路径找到当前目录下的内容

image-20230819030346137

最后是无环图目录结构,该结构可以令不同的文件名指向同一个文件,使得整个目录看起来像一个有向无环图,因此得名无环图目录结构

每一个共享在不同用户的文件都有共享计数器,当用户删除时,只是删除该用户的FCB并令共享计数器-1,当共享计数器的值为0时,则会真正删除该文件内容

image-20230819030539118

索引节点指的是在FCB查找时利用的内容都是其文件名,既然如此就可以将其他内容提取出来形成一个索引节点,那么最开始的目录结构就存储文件名和索引节点指针即可,使用该方式可以令一个磁盘块下存储更多目录,这样对于相同目录下的扫描就可以少扫描一些磁盘块,这样就可以减少IO次数(每次磁盘启动IO读入一块磁盘块),因此其可以提高搜索速度

image-20230819031001179

存放于外存中的索引节点称为磁盘索引节点,当其放入内存后被称为内存索引节点,后者比前者会添加多一些信息,比如文件是否被修改,此时有几个进程正在访问该文件等

image-20230819031035812

最后我们来看看总结

image-20230819031101650

文件的物理结构

操作系统需要对非空闲磁盘块和空闲磁盘块都进行管理,我们这一节主要讲对非空闲磁盘块的管理

image-20230819034858814

文件的物理结构也就是文件分配方式有连续分配、链接分配、索引分配三种,其中链接分配具体可以细分为隐式链接和显式链接两种

image-20230819034939089

外存中的存储单元会被分为一个个磁盘块,其大小与内存块和页面的大小相同,因为内存与磁盘之间进行的数据交换都是以块为单位进行的,那么如果这两者中的块大小是一样的,对于实现数据交换来说就会比较便利

image-20230819035026723

在外存管理中,文件的逻辑地址空间被分为一个个块,所以文件的逻辑地址可以表示为(逻辑块号,块内地址)的形式,下图中可以看到逻辑块号对应每一块文件区,每一块中具体还有块内地址的细分

image-20230819035611583

在连续分配方式中要求每个文件在磁盘中都占有连续的块,其逻辑地址到物理地址的转换非常简单,就是物理块号=起始块号+逻辑块号,文件目录的FCB中是有记录起始块号的和长度的,当然还需要转换时还需要检查用户提供的逻辑块号是否合法,也就是是否超过了记录的长度

image-20230819035920507

连续分配的文件在顺序读/写时速度最快

image-20230819040151823

其缺点有两个,第二个是物理上采用连续分配的文件不方便拓展

image-20230819040243514

第二个缺点存储空间利用率低,会产生难以利用的磁盘碎片,当然可以利用紧凑来处理碎片,但是要耗费很大的时间代价

image-20230819040343385

而链式分配采取离散分配方式,分为隐式链接和显式链接两种

image-20230819040709707

隐式链接指的是在目录FCB中保存了文件的起始和结束块号,而各个块之间的联系关系只有在操作系统具体访问到磁盘块中才可以找到,这就导致该方法只支持顺序访问,不支持随机访问,随机访问的意思就是说可以直接访问任意一个数据而不用从跟第一个开始访问直到访问到为止

其文件从逻辑块号的物理块号的转变其实就是知道起始块号之后不断访问,可以理解为起始块号就是物理块号

image-20230819040836936

这种方式也很方便拓展文件同时不会有碎片问题,外存利用率高

image-20230819041024007

而显式链接的方式指的是各个磁盘块的连接不是存在于磁盘块中,而是用文件分配表FAT进行记录,其实就是整一个静态链表来表示各个物理块的静态关系,由于FAT是存在于内存中的,因此其查询到目标磁盘块的速度非常快

image-20230819041300961

而在显示链接中逻辑块号转换成物理块号的过程不需要读磁盘操作,可以直接在FAT中完成,支持随机访问的同时也不会产生什么外部碎片,转化方式其实简单理解就是下一块地址和起始块号就是物理地址

image-20230819041522906

最后我们来看看上面学习的内容的总结

image-20230819041614613

索引分配中系统会给每个文件建立一张索引表,其中记录了文件的各个逻辑块对于的物理块,按照顺序记录,索引表存放的磁盘称为索引快,而文件数据存放的磁盘称为数据块,比如咋下图中可以看到起连接顺序是2、5、13、9,因此其逻辑块号从0到3就是2、5、13、9

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

image-20230819044901302

索引分配方式里,FCB只需要记录文件名和索引块以及其他内容,这个方式唯一的缺点就是索引表也需要占用一定的存储空间

image-20230819045036004

由于索引分配中要求一个索引表最大不能超过一个磁盘块,那如果一个文件真的太几把大了,其索引表大小必然会超过一个磁盘块该怎么办?这种情况有三种解决方案,分别是链接方案、多层索引、混合索引

image-20230819045140033

链接方案指的是如果索引表太大,那么可以将多个索引块连接起来存放,其中索引块之间的关系是索引块内部自己链接的,FCB中只保存第一个磁盘大小的索引表起始内容,这种方式的问题是在面对大文件时可能会出现极度低效的情况

image-20230819045402187

多层索引的原理类似于多层页表,简单来说就是建立多层索引来应对大文件,每个索引的大小都不能超过一个磁盘块,FCB中存储一级索引表的地址,要寻找第几个索引块只要通过对于的/和%操作即可,比如在下图中要求找到第1026号逻辑块,那么已经知道一个磁盘块的大小为256B,那么由于1026/256=4,1026%256=2,所以说起显然要查找一级索引的第四个表项同时要找起地址为2的内容

采用这种方式,如果采用K层索引结构,那么访问一个数据块需要K+1个读磁盘操作

这个方式的问题是即使磁盘块很小,也需要进行K+1次访问才能成功访问到,这样显然是拖慢的效率

image-20230819045821094

混合索引指的是多种索引分配方式的结合,其下有直接地址、一级间接和二级间接等索引,直接索引指的是该索引直接对于一个磁盘块,而一级间接索引指的是对应一个索引块,而二级间接索引就是指的是对应一个二级索引块,这种方式可以解决小文件还要多次读磁盘的问题

image-20230819050150178

注意考点是要通过多层索引、混合索引的结构计算出文件的最大长度以及自己计算机访问某个数据块需要的读磁盘次数(注意题有无已调入顶级索引块进入内存)

image-20230819050526104

最后如果题目中只是说了链接分配方式,那么一般来说我们认为是隐式链接

image-20230819050621676

逻辑与物理结构对比

下面我们来讲下文件中的逻辑和物理结构的对比

image-20230819052927072

我们先用一个C语言代码创建一个无结构文件

image-20230819053101803

用户可以通过指定逻辑地址空间来获取指定的内容,对于用户来说这个文件好似就存储在一片连续的空间里

image-20230819053226339

而对于操作系统来说,这些内容都是串二进制数,直接咋磁盘块中存就完了,至于到底是使用什么方法来存的,这个事就是由操作系统自己决定了

image-20230819053558524

对于有结构文件来说也是一样的,比如我们下面利用C语言创建有结构文件

image-20230819053911342

对于操作系统来说,跟上面是一样的,而在用户看来,也是像文件存储到了一个连续的空间里一样

image-20230819054221260

之后的内容都是一样的,自己看图吧,这里不重复提及了

image-20230819054346579

image-20230819054507031

image-20230819054657127

image-20230819054814852

最后我们来看看总结

image-20230819054852277

文件存储空间管理

接着我们来继续文件存储空间管理,我们这里将对空闲磁盘块的管理

image-20230819092051844

首先存储空间会划分为多个盘,每个盘称为文件卷或数据卷,每个数据卷会继续细分为目录区和文件区,前者存放文件目录信息,也就是FCB,一般用于磁盘存储空间信息的管理,而后者用于存放文件数据

值得一提的是,有些系统支持多个物理磁盘组成一个文件卷,不过这些系统一般我们接触不到就是了

image-20230819092253929

存储空间管理方法有多个,我们先来介绍第一种空闲表法,其适用于连续分配方式,工作逻辑是记录空闲盘号以及盘块数目,这样形成的空闲盘块表可以表示磁盘中所有的空闲盘块,其为文件分配连续的存储空间时可以采用我们之前学习过的首次适应、最佳适应、最坏适应等算法

image-20230819092449521

其回收磁盘块的方式和之前我们学习过的动态分区的分配很类似,反正都回收之后前后都没有相邻的空闲区就新增一条记录,反之则合并

image-20230820010325828

然后是空闲链表法,该方法具体还可以细分为空闲盘块链和空闲盘区链,前者指的是以盘块为单位组成一条空闲链,其实就是空闲的盘块组成链表,而后者指的是多个连续的盘块会组成一个盘区,同时每个盘区的第一个盘块会指向下一个盘区,这个其实非常像哈希表的存储方式说实话

image-20230820010444688

我们先来将第一种方法,第一种方案分配空间时如果文件申请K个盘块,那么就会从开始依次选择K个盘块分配并修改空闲链的链头指针,链头指针指向新的空闲盘块,而对于要回收的盘块则直接将其挂到链尾并修改空闲链的链尾指针,由于这终究是个链表法,因此链头链尾的概念很好理解,我们这里总是维护着链表的头结点和尾结点来实现,这个方法适用于离散分配的物理结构

image-20230820010634768

而空闲盘区链法分配空间时也可以采用首次适应等算法,同时会从头结点开始搜索找到一个大小符合要求的空闲盘区进行分配,如果没有合适的连续空闲盘区,其会将不同盘区的盘块同时分配给一个文件,当然分配之后要修改响应的头尾节点的指针和盘区大小

而对于回收盘块,如果回收盘块和某个空闲盘块相邻就会直接将该回收区合并到空闲盘区中,反之则将该盘块挂到链尾作为一个新的盘区

该方法对于离散和连续分配时都适用且对一个文件分配多个盘块时的效率更高

image-20230820010901922

位示图法是我们考试中非常重要的方法,这里表现空闲磁盘块的逻辑时建立一张横为位号竖为字号的表,其中每一个字块的值表示该盘块是否已经被利用,0表示没有,1则反之,这里的一个位置的盘块可以用(字号,位号)表示,一个位置的盘块=字号*(横长度)+位号,而如果已经知道了盘块字号,则要求其字号则是令其除于横长度取商,求位号令其除于横长度取余

image-20230820011126737

其分配时会顺序扫描位示图,找到所需要的相邻或不相邻的0号位并分配且将对于分配的位置的值置为1,回收时则根据回收的盘块号计算出对于的字号位号然后将相应位置的值置为0

image-20230820011316499

空闲表发和空闲链表法都不适用于大型文件系统,因为空闲表或空闲链表都可能过大,而在UNIX系统中则采用了成组链接发对磁盘空闲块进行管理

文件卷的目录区中有一个磁盘块作为超级块,系统启动时需要将超级块读入内存并且保存内存和外存中的超级块的数据一致

image-20230820011415213

超级块中存储着下一组空闲的盘块数和所有的空闲块号,而系统可以根据这些空闲块号找到空闲的磁盘块,而这些磁盘块也跟超级块一样除了存放其自己的内容之外还存放了自己的下一组的空闲盘块书和所有的空闲块号,而如果已经没有了下一组空闲块,那么其下一组空闲盘块数的值为设为某个特殊值,比如说-1

值得一提的是在该分配方法中分组并不要求连续,我们这里连续主要是方便教学,然后是每个分组的空闲盘块都是有上限的,比如我们这里就是100

image-20230820011851327

其分配空闲块是的逻辑时如果头结点分组的块数足够分配且小于该分组的空闲块数,那么会直接分配其第K个空闲块给文件并修改对于的空闲块数

image-20230820012119170

如果正好是和空闲块的数量相等了,说明此时该分组的所有空闲块分配完就没有空闲块了,那么其就会复制其下一组的空闲块内容到那边,这个动作其实就是相当于链表中把头结点下一个链表成为头结点,这里要这么做是因为头结点总是要放空闲块的,所以直接拿下一组的内容代替称为头结点就行了

image-20230820012242867

而回收时优先加到头结点中,无非就是回收之后将对于空闲块加入到该分组的空闲块号中并修改其空闲数量,当然,这里的前提是回收之后头结点的空闲磁盘块不会超过指定的最大值

image-20230820012712411

如果要回收的磁盘块超过的最大值,那么就会令头结点的内容移动新节点里,而自己则回收最新的磁盘块并指定对于值,这里做的动作其实就是将头结点设定为最新的节点,也很好理解

image-20230820012840905

最后我们来看看总结

image-20230820012912928

文件的基本操作

操作系统给上层应用提供了对应的基本功能,我们本节就来学习这些内容

image-20230820021947886

首先是创建文件的功能,当用户选择创建文件时,其实是调用了操作系统提供的crreate系统调用,其需要提供三个参数分别是文件所需的外存空间大小、文件存放路径、文件名,操作系统处理该系统调用时主要做了在外存中找到文件所需的空间和创建文件对应的目录项这两件事

image-20230820022121503

而删除文件则是调用delete系统调用,其需要提供文件存放路径和文件名两个参数,系统对其进行的处理分别是找到文件对应的目录项、回收文件占用的磁盘块以及删除文件对应的目录项

image-20230820022501831

而打开文件调用open系统调用,需要提供文件存放路径、文件名以及要对文件的操作类型这三个参数,操作系统会找到文件名对于的目录项并将目录项复制到内存中的打开文件表中,这样用户可以通过使用打开文件表的编号来指明要操作的文件,不用每次都重新查找目录来操作文件

image-20230820022801971

注意系统也有一个打开文件表,里面记录文件有一个记录项是记录该文件被几个进程打开,如果该文件被一个进程打开的话,那么就不会允许其他删除或者修改等动作,而每个用户也有一个打开文件表,其中有系统表索引号,其实就是指向相同文件但是在系统的打开文件表的记录位置

image-20230820023136255

关闭文件调用系统提供的close系统调用,其处理的事就是将进程的打开文件表的相应数据项删除并回收其内存空间等资源,同时系统打开文件表的打开计数器会-1,如果其值为0,那么会删除其对于表项

image-20230820023314996

读文件调用read系统调用,需要指明是读哪个文件(在支持打开文件的系统中,只需要提供文件在打开文件表中的索引号就行了),以及要读入多少数据和读入的数据要放在内存中的什么位置,操作系统会将读指针指向的外存将用户指定大小的数据读入用户指定的内存区域中

image-20230820023552225

写文件调用write系统调用,其需要指明是哪个文件、该文件要写出多少数据以及写出的数据要写在内存中的什么位置,操作系统会将指定大小的数据写回写指针指向的外存

image-20230820023735578

最后我们来看看总结,值得一提的是有时索引号也称为文件描述符

image-20230820023831629

文件共享

文件共享有两种方式,分别是基于索引结点的共享方式和基于符号链的共享方式,前者称为硬链接,后者成为软链接

image-20230820031233564

如果采用硬链接,那么当多个用户共享一个文件时,索引结点中会设置一个链接技术变量count,其记录链接到该文件索引上的用户目录项数,用户删除文件只会将自己文件上的目录删除,同时该count会-1,如果count!=0,则不能删除该文件,反之则会自动删除

image-20230820031603250

如果采用软连接,则索引结点指针会指向一个count=1的文件物理地址的节点,该文件是要共享的文件的Link类型的文件,其内部记录共享文件的存放路径,这个类似于Windows的快捷方式

image-20230820032011495

我们在自己的Windows系统的电脑中也是可以验证这一点的

image-20230820032140679

软连接的问题是可能会出现Link文件无效的情况,因为可能Link文件指向的文件已经被删除了,而Link文件还没删除

image-20230820032304528

最后我们来看看总结

image-20230820032354770

文件保护

文件保护有三种方式,分别是口令保护、加密保护以及访问控制

image-20230820034533656

口令保护非常好理解,其实就是设置一个密码,用户访问时必须输入该密码才能访问改文件,不过这里我们的密码称为口令,口令一般存放在文件对应的FCB或索引结点中,这个方法的好处是开销很小,缺点是因为口令存放在系统内部,所以不够安全

image-20230820033208838

第二种加密保护的方式是对文件进行加密,访问文件时必须提供正确的密码才能解密,如果提供不正确的密码,那么得到的就会是无意义的二进制码,因为加密会将整个文件都保护起来,该方式的优点是保密性强,缺点是加密解密需要花费一定时间

image-20230820033418904

访问控制方法指的是在各个文件的FCB中增肌一个访问控制列表,该表记录各个用户可以对文件执行哪些操作,比如说最简单的CURD

image-20230820033659036

当然,如果计算机的用户太多,那么访问控制列表可能会很大,为了解决这个问题可以使用以组为单位的精简的访问列表,这个跟Linux的组概念几乎是一致的,我这里就不赘述了

image-20230820033757247

最后我们来看看总结

image-20230820034159499

层次结构

操作系统的文件管理的层次结构如下所示

  1. 用户接口,主要用于向上层提供简单的功能接口(Read、Write、Open、Close)以及用于处理用户发出的系统调用请求
  2. 文件目录系统,主要根据用户给出的路径找到相应的FCB或索引结点,所有的目录和目录项相关的管理工作都在本层完成
  3. 存取控制模块,主要用于保证文件数据的安全,用于验证用户是否有访问权限以及完成文件保护的相关功能
  4. 逻辑文件系统与文件信息缓冲区,该层会将文件记录号转换为对于的逻辑地址,同时信息缓冲区主要用于引入文件索引结点
  5. 物理文件系统,主要用于将文件的逻辑地址转换为实际的物理地址
  6. 辅助分配模块用于负责文件的分配和回收工作,而设备管理模块则直接和硬件交付,负责分配调度、磁盘调度等工作

image-20230820035838771

我们可以用下图的例子来加深我们对文件管理层次结构的理解

image-20230820040006525

全局结构(布局)

接着我们来介绍文件管理的全局结构,首先是没有任何内容的原始磁盘

image-20230820041111688

然后进行物理格式化,也就是低级格式化,其会将磁盘划分为一个个扇区,扇区存在坏扇区和备用扇区,对于操作系统来说,他是不知道自己使用的扇区是不是坏扇区的,但是负责磁盘的进程是知道的,当操作系统使用扇区时,其会检测该扇区是否为坏扇区,若是则使用备用扇区替换坏扇区

image-20230820041247636

然后进行逻辑格式化,逻辑格式化会将磁盘进行分区,分成一个个数据卷,也就是不同的盘块,完成各个分区的文件系统初始化,磁盘中会有主引导记录MBR,其包含磁盘引导程序和分区表,前者的内容不记得就去看第一章,后者则是记录该磁盘的各个数据卷的分布情况的,这样才能正确得到分区情况

我们可以在数据卷中建立操作系统,一般来说都是C盘,比如下图中是UNIX文件系统,其存在引导块,负责开机时的初始化操作系统,超级块和空间空闲管理的内容我们上面都学过了就不提了,i结点区其实就是索引结点区,这里的索引结点是顺序存储的,所以也支持随机访存,根目录是初始化之后就有的目录,其他白色部分的内容则是等待用户添加的内容

image-20230820041633871

上面我们介绍的结构都是外存的,而在内存中分为用户区和内核去,内核区中会缓存用户最近打开的目录,根据局限性原理这样做可以提高效率,然后存在系统打开文件表和进程打开文件表,前者在系统中只有一个,而后者有多个,在用户区中则存在文件描述符和文件句柄

当用户打开一个目录中的文件时,该目录首先被加入到内核区中的缓存中,找到内核区会根据缓存找到目标文件的FCB,复制到系统打开文件表,其中存在文件A的FCB内容的地址,接着同时在用户打开文件表中添加对应的的记录,该记录有打开方式和指向系统打开文件表相同记录的地址,在用户打开文件表中添加好条目之后返回一个文件描述符fd给用户,用户可以根据该文件描述符执行系统调用的方法,比如read方法就只要传入fd和必要的参数就可以执行

image-20230820042132245

虚拟文件系统

在文件管理中,可能会存在多个文件系统,分别对于不同的设备,每个文件系统的函数肯定是存在差异的,这样用户进程如果想要调用其函数,那么就会增加编程上的难度

image-20230820044356216

为此出现了虚拟文件系统,向下能调用不同文件系统的相同函数,向上能提供给用户进程统一的接口,简单来说就是加一层封装其实,跟JDBC类似

image-20230820044527207

虚拟文件系统VFS要求下层的文件系统必须实现规定的函数功能这样方便其调用函数

image-20230820044541607

不同的文件系统其文件结构是各不相同的,这样会造成VFS在数据展示上的不直观

image-20230820044805959

因此VFS指定了vnode,简称v结点,所有不同文件系统上的数据最终会复制到这个v结点上以实现数据的统一展示

image-20230820044856005

这里要注意的是v结点只存在于主存中,而inode,也就是索引结点是既会被调入主存,也会被调入外存中存储

image-20230820045028405

v结点中有一个函数功能指针的数据项,其存储对应的文件系统函数的系统调用,也就是一个指向具体函数功能的指针,这样用户对该文件执行对应的系统调用是操作系统可以直接通过该结点的函数功能指针找到对应的系统调用并执行

image-20230820045223024

文件系统挂载指的是文件系统的安装或卸载,我们日常生活中经常接触这个,比如我们插U盘其实就有在做文件系统挂载的事

挂载文件首先要在VFS中注册新挂载的文件系统,内存中会维护一个挂载表,注册就是将该文件系统的相关信息,比如系统类型、容量大小等内容记录到该表中,接着新挂载的文件系统要向VFS提供其函数地址列表便于VFS对其函数的调用,最后要将新文件系统加到挂载点,也就是将新文件系统挂载到某个父目录下,这个听起来很抽象,实际就是我们插入U盘时我们可以看到一个新的盘,这个其实就是新的磁盘加载到我们的某个目录并展示到那里的结果

image-20230820045546681

IO设备的概念和分类

本节我们介绍对设备的管理,我们使用的设备基本都是IO设备,本节我们先来介绍IO设备

image-20230821130852309

I/O指的就是输入/输出,鼠标键盘是典型的输入型设备,显示器是输出型设备,而移动硬盘是既可输入又可输出的设备

image-20230821131001660

IO设备可以按照使用特性分类

image-20230821131604182

可以按照传输速率分类

image-20230821131649242

可以按照信息交换单位分类

image-20230821131734386

最后我们来看看总结

image-20230821131756785

IO控制器

IO设备由机械部位和电子部位组成

image-20230821141320247

机械部位主要用于执行具体的IO操作,比如鼠标的按钮就是用来执行用户打入什么字的,而电子设备通常是一块插入主板扩充槽的印刷电路板

image-20230821141443623

CPU是无法直接控制IO设备的机械部件的,因此IO设备产生了电子部件来作为CPU和IO设备部件之间的中介,用于实现CPU对设备的控制,其又称IO控制器或设备控制器,同时其也控制IO设备的机械部件

其可以接受和识别CPU发出的命令,其控制器里有控制寄存器来存放命令和参数、存在状态寄存器用于记录IO设备的当前状态、存在数据寄存器用于暂存CPU或是IO设备发送过来的数据,同时其下的数据可以被CPU或IO设备取走进行展示、最后其提供地址识别功能,这样可以区分其下的各个寄存器,其会通过CPU提供的地址来判断CPU要进行读写的是哪个寄存器

image-20230821141718927

IO控制器有三大块,分别是用于实现CPU与IO控制器之间通信的CPU与控制器之间的接口、负责接受和识别CPU各种命令并对设备发出命令的IO逻辑、用于实现控制器与设备之间的通信的控制器与设备的接口

CPU上会有地址线和控制线连接IO逻辑,地址线负责提供要执行命令的寄存器的地址,控制线提供要执行的命令,同时在CPU与控制器的接口间的各个寄存器里有一条数据总线连接CPU与与各个寄存器,这样CPU可以从各个寄存器里取数据,同时各个寄存器和IO逻辑有连接,这个很好理解,不然IO逻辑怎么操作寄存器不是,同理IO逻辑对控制器与设备的接口也有连接

这里值得一提的是控制器与设备的接口有三个功能,一个是传入传出数据,第二个是像IO逻辑报告自己的状态,第三个是向设备发出相应的控制信息

image-20230821142205448

注意,一个IO控制器可能会对应多个设备同时数据/控制/状态寄存器可能有多个且这些寄存器都有相应的地址,有些计算机会让这些寄存器占用内存地址的一部分,这称为内存映像IO,另一些计算机则采用IO专用地址,称为寄存器独立编址,后者具有需要CPU额外指明控制器编号的缺点,而前者则没有

image-20230821144735893

image-20230821144906620

最后我们来看看总结

image-20230821144926770

IO控制方式

本节我们来学习IO控制方式,也就是CPU用什么方式来控制IO设备的读和写,其一共有程序直接控制方式、中断驱动方式、DMA方式和通道控制方式

image-20230822085609614

程序直接控制方式的核心方式是轮询,当CPU要进行读写时,会向IO控制器(后续简称控制器)发出指令,同时令寄存器状态设为1,也就是令寄存器除于忙碌/未就绪状态,然后CPU会轮询检查控制器状态,只要未1说明寄存器还没收到IO设备的数据,也就是还没准备好,就会继续轮询,当IO设备准备好数据后会将数据传给控制器并报告给控制器其已经处于空闲状态,控制器会将数据放到数据寄存器中且将该寄存器的状态置为0,也就是说明该寄存器已经就绪了,准备好数据了,此时CPU轮询发现设备已经就绪,就会将其中的数据读入CPU的寄存器中,最后将CPU的寄存器放入到内存

image-20230822090509401

其流程图如下所示,可以看到最开始是CPU向IO控制器发出指令,而每次检查状态时由于设备本身可能出现错误,因此还准备了错误条件,如果发生了错误会将该错误信息放到寄存器中,然后被CPU读取到

这里CPU从寄存器中取出数据后还会将数据写入到存储器中,这么做是一位输入的数据最终还要是放到内存中的,比如我现在打字,CPU获取到了那肯定要显示在屏幕中的吧?这个屏幕展示的字其实就是存储器中到内存的字,所以CPU最后还需要将数据写到存储器中,而输出的数据对此也是同理的

image-20230822094251767

该方式的问题在于CPU和IO设备只能串行工作,CPU和IO设备的利用率都很低,而且每次传输只能读写一个字

image-20230822094620822

为了解决效率低的问题,提出了中断驱动方式,其引入中断机制,可以将等待IO结果的进程阻塞,令CPU先去做别的事情

其执行逻辑是当CPU的进程给IO模块发出命令之后会令等待IO结果的进程中断,令其他进程执行,当IO设备完成时,会向CPU发送中断信号,CPU检测到中断信号之后会转而执行等待IO设备结果的进程,执行完毕后再恢复

这里要注意CPU会在每个指令周期的末尾检查中断,同时中断过程处理需要保存、恢复进程的运行环境,同时如果中断频率太高也会降低系统性能

image-20230822094837646

该方式优点是可以实现并行工作,CPU的利用率有明显提升,缺点是频繁的中断会消耗过多的CPU时间

image-20230822095130325

而主要用于块设备的IO控制的DMA方式又称直接存储器存储方式,其运行逻辑是CPU向DMA指定本次要执行的操作、要读入多少数据、数据要存放到内存的什么位置以及数据在外部设备上的地址,然后CPU就做其他事情了,DMA会负责完成接下来原本属于是CPU的任务,当DMA完成任务后会向CPU发出中断信号

image-20230822095426458

DMA控制器和结构和IO控制器的结构差不多,都有主机控制器接口、IO控制逻辑以及块设备控制器接口,其中主机控制器接口多个寄存器,用于存储CPU指定DMA要做任务的必要信息以及一些数据

image-20230822095802323

注意这里DMA到磁盘以及DMA到内存的数据读取其实还是按字读取的,只是每次要读取到至少一个块的数据而已,而且这个块数据必须是连续的

该方式的优点是可以进一步提升CPU和IO设备的效率,缺点是CPU每次发出一条IO指令就只能读一个或多个连续的数据块,不能一条指令读多个离散的数据块

image-20230822100025032

通道控制方式中的通道是一种硬件,可以理解为是垃圾版CPU,其可以识别并执行一系列通道指令,CPU会首先发出IO指令,指明通道程序在内存中的位置以及要操作哪个IO设备,之后CPU就忙自己的额去了,通道会执行通道程序,这个通道程序其实就是任务清单,也就是说通过通道程序可以执行多个任务,这样就解决了DMA方式一个CPU发送一条指令只能读取一个块的问题,通道执行完之后同样会向CPU发送中断信号

image-20230822100240707

通道之所以说是垃圾版的CPU,因为通道可以执行的指令单一且是放到主机内存中的,其与CPU共享内存,有一条数据总线连接CPU内存和通道,其每次读写的单位是一组数据块,其最大的优点是CPU、通道、IO设备可以并行工作,资源的利用率很高

image-20230822100355019

最后我们来看看总结

image-20230822100445261

软件层次结构

接着我们来讲IO软件层次结构,可以看到下面IO软件的层次结构一共分为五层,从上往下分别是用户层软件、设备独立性软件、设备驱动程序、中断处理程序、硬件,上层可以调用下层的函数,下层为上层提供具体的服务,这个非常像计网其实,中间设备独立性软件、设备驱动程序、中断处理程序属于操作系统的内核部分,称为IO系统或IO核心子系统

硬件就是我们上面学过的内容,我们这里就不赘述了

image-20230822233052549

用户层软件实现了与用户交互的接口,用户可以直接使用该层函数对设备进行操作,同时其将用户请求通过系统调用请求操作系统内核的服务,当然对应的系统调用也会被填入响应参数,其中由于Windows操作系统调用的格式严格,因此用户层其实还封装了一系列更方便的库函数接口供用户使用

image-20230822233402327

设备独立性软件层就跟其名称一样,和设备没啥关系,主要提供设备保护和差错处理等功能

image-20230822234828445

该层会建立并维护逻辑设备到物理设备名的映射关系,如下图所示,分为三列记录了逻辑设备名、物理设备名以及驱动程序的入口地址,之所以要记录驱动程序入口地址是因为不同类型的IO设备需要不同的驱动程序进行处理

操作系统可以采用两种方式管理逻辑设备表(LUT),第一种方式是整个系统只设置一张表,其问题在于所有用户不能使用相同的逻辑设备名,只适合于单用户操作系统,第二种方式是给每一张用户都设置一张LUT,适合多用于操作系统,用户登录就为其建立用户管理进程,而LUT就存在其管理进程的PCB中

image-20230822233755012

之所以不同的IO设备需要不同的驱动程序,是因为不同的打印机内部电路和处理逻辑可能都大不相同,因此需要厂家提供驱动程序,这样CPU只要对驱动程序进行对于的操作就可以令打印机执行预期操作了

image-20230822233938028

设备驱动程序主要负责对硬件设备的具体控制和对上层发出的一系列命令的转化,注意驱动程序一般会以一个独立进程的方式存在

image-20230822234037975

中断处理程序就很好理解了,反正是用于处理中断的程序

image-20230822234227418

注意,设备驱动程序和中断处理程序是会直接和硬件打交道的,其他层则不会

image-20230822234341956

别忘了逻辑设备表LUT的相关知识,这很重要

image-20230822234401145

输入输出应用/驱动程序接口

本节学习下图中的内容

image-20230823001430752

由于硬件中有多种设备,用户层无法用一个统一的接口调用这三个方法,因此设备独立软件层提供了三个不同的接口用于用户调用不同的设备

image-20230823002048696

字符设备接口由于没有读写指针的说法,因此只是调用get/put系统调用来进行读写字符,而快设备有读写指针,因此其系统调用需要用到读写指针读写字符,通过seek系统调用修改读写指针位置,而网络设备接口,又称网络套接字(Socket)接口,其使用socket系统调用,其会创建一个网络套接字并指明网络协议,使用bind将套接字绑定到本地端口,通过connect将套接字连接到远程地址,最后通过read/write方法从套接字读写数据

image-20230823002447037

光说就太抽象了,直接来举个例子吧,比如现在有三台主机,那么首先主机2需要就创建一个网络套接字,这个其实相当于是申请了一片内核空间,然后指定要是用的传输协议(TCP/UDP),接着绑定端口号,基本就完成了本地用户到互联网的连接了,另一个主机也是如此

当一个主机想要和另一个主机传输数据时,且可以先写数据,然后通过connect方法将套接字连接到远程地址,这里的过程首先数据会被放到socket框中,如下图所示,可以理解为这个是socket的缓冲区,然后会传输到对应主机的内核空间的缓冲区上,当该主机要取出数据时就会调用read方法取出该数据并展示

image-20230823003343513

阻塞IO指的是应用程序发出的IO系统调用时进程需要转为阻塞态等待,而非阻塞IO则反之,进程无需等待

image-20230823003556479

操作系统规定设备驱动的接口必须有一个统一的标准便于操作系统调用

image-20230823003714618

不同的操作性提供对设备驱动程序的接口标准也不相同

image-20230823003758776

核心子系统

设备独立性软件、设备驱动程序、中断处理程序这三层总称为IO核心子系统,我们需要重点理解其实现的IO调度、设备保护、假脱机技术、设备分配与回收、缓冲区管理等内容

image-20230823010046713

假脱机技术又称SPOOLing技术,其在用户层软件实现,不过其实现要调用设备独立性软件的一些内容,而IO调度、设备保护等内容则是在设备独立性软件层实现

IO调度指的是用某种算法确定一个好的顺序来处理各个IO请求,比如我们之前学过的先来先服务算法等

image-20230823010349802

而设备保护其实本质是文件保护功能,其是将设备看做一种特殊的文件,那么其就会有一个对于的FCB来实现文件保护功能

image-20230823010509063

接下来我们就一个个讲解这些技术

image-20230823010544513

假脱机技术

本节我们来介绍假脱机技术

image-20230823011420350

早期的主机没有脱机技术,人机交互速度慢,效率特别低

image-20230823011724057

后来引入了脱机技术,就是引入了外围控制机,这样用户可以通过外围控制机先将纸带写入在磁带,磁带可以在CPU空闲时被CPU输出,这样就提高了效率,同时即使CPU在忙碌,也不影响用户将数据通过外围控制机加载到磁带上,输出时也是同理

之所以这样的技术叫脱机,单纯是因为这个操作脱离了主机的控制,所以叫脱机,就是这么简单

image-20230823011920497

而假脱机技术指的是用软件的方式来模拟脱机技术,其系统的组成如下图所示,可以看到其在磁盘会申请输入井和输出井,这两个其实是在模拟上图中的读写时的磁带,同时在内存中还有输入/输出进程,这个是在模拟上面的读写时的外围控制机,在内存中还有输入/输出缓冲区,其就相当于是内存中的缓冲区,数据在设备和井之间的传输时就会暂存在此

image-20230823012239954

独占式设备只允许各个进程串行执行,也及时一段时间内只能有一个进程执行,而共享设备是允许多个进程并发执行的设备,也就是在微观上是多个进程交替使用CPU,但是宏观上看起来就是大家一起使用的,而SPOOLing技术可以将独占式设备改造成共享设备

image-20230823012446232

比如在共享打印机中,原本是串行运行的,但是引入SPOOLing技术之后,当有多个用户申请打印机资源时,其首先会接受,然后在磁盘输出井中为进程申请一个空闲缓冲区,然后将要打印的数据送入其中,再为用户进程申请一张空白的打印请求表,将用户的打印请求的具体数据填入再将其挂到假脱机文件队列中,当打印机空闲时会从文件队列的队头取出打印请求表进行打印任务

image-20230823012657447

其原理是将物理设备虚拟成逻辑上的多台设备,将独占式设备改造成共享设备

image-20230823012743169

最后我们来看看总结

image-20230823012800265

设备的分配与回收

设备分配时应该考虑多个因素,本节我们来学习这些

image-20230823015014171

首先设备可以分为独占设备、共享设备以及虚拟设备,其中虚拟设备指的谁使用SPOOLing技术将独占设备改造而成的共享设备,本质是个虚拟设备,这些就是设备的固有属性,设备分配时首先要考虑这点

image-20230823015108072

其次设备分配时应该要考虑设备的分配算法,其实就是我们之前学习过的先来先服务等算法

image-20230823015202169

最后设备分配时要考虑设备在分配中的安全性,设备分配从安全性考虑有两种方式,分别是安全分配方式和不安全分配方式,前者是为进程分配一个设备后就将进程阻塞直到IO完成,其优点是破坏了构成死锁的“请求和保持”条件,缺点是效率低,因为CPU和IO都只能串行工作了,后者是一个进程分配IO设备后不会阻塞直到某个IO请求得不到满足,其优点是效率高,允许并行,缺点是有可能发送死锁

image-20230823015349321

设备分配有静态分配和动态分配,前者指的是运行前为其分配全部的所需资源直到运行结束后归还,后者指的是进程运行过程中再获取其他资源

image-20230823015536486

一个通道控制多个设备控制器,一个控制器控制多个设备,具体为下面的树状图

image-20230823015703588

系统为了管理设备、控制器、以及通道,给其都设置了对于的表,我们一个个介绍,这里我们只介绍重要的,其他的自己看图吧

首先设备有设备控制表DCT,首先设备被控制器控制,因此设备有指向控制器的指针,同时设备表还有一个设备队列的头指针,其指向正在等待该设备的进程队列(由进程PCB组成队列),设备有可能IO操作不成功,但是不成不意味着IO失败,因此有记录执行次数或时间的字段,当多次IO操作不成时,操作系统就会认为此次IO失败并进行对应处理

image-20230823015842033

进程控制器表COCT,由于每个控制器都有一个通道控制,因此其有指向通道的指针,同时控制器队列的首尾指针,指向正在等待该控制器进程队列

image-20230823020013420

通道控制表CHCT,由于通道管理所有控制器,因此其有指向第一个控制器的指针,通道可以根据该指针找到其管理的所有控制器的相关信息,同时也有指向等待该通道的进程队列

image-20230823020139265

系统中还有系统设备表SDT,其记录了系统中全部设备的情况,每个设备对于一个表目,表目内部除了驱动程序入口外还有DCT和一些必要属性

image-20230823020226626

首先操作系统根据进程请求分配设备时,其首先根据进程请求时提供的物理设备名根据SDT查找对应的表目

image-20230823020303230

查找到之后通过表目中的DCT指针查看设备是否忙碌,若忙碌则将进程挂到其等待队列中,反之则将设备分配给该进程

image-20230823020335141

然后根据DCT中的指向控制表的指针查找COCT,若忙碌则将进程挂到该控制器的等待队列,反之则分配

image-20230823020405222

接着根据COCT中指向通道表的指针查看通道是否忙碌,若忙碌则将该进程挂到该通道的等待队列中,反之则分配

注意只有当设备、控制器、通道三者都分配成功时,这次设备分配才算成功

image-20230823020439321

这种分配方法的缺点是必须使用物理设备名,同时即使进程中有同类型的设备,进程也必须阻塞等待,导致效率不佳

image-20230823020625802

其改进方法是建立逻辑设备名与物理设备名的映射机制,其实我们就是我们之前讲过的逻辑设备表LUT,改进之后系统首先根据逻辑设备名查找SDT中的设备,找到一个指定类型且空闲的设备之后就将该设备分配给进程,同时在LUT中增加一个记录表项,后面的过程就跟上面一样了

image-20230823020731631

当用户进程再次通过相同的逻辑设备名请求设备时,就不用查找了,直接通过LUT表就能知道用户进程实际要用的是哪个物理设备,也能知道该设备的驱动程序入口地址,直接调用即可

image-20230823020847776

最后我们来看看总结

image-20230823020923215

缓冲区管理

本节我们来介绍缓冲区相关内容

image-20230823025148006

缓冲区是一个存储区域,可以由专门的硬件组成,但是成本较高,一般仅用在对速度要求非常快的场合,比如快表,一般情况下我们还是利用内存作为缓冲区的

image-20230823025326532

缓冲区具有提高CPU和IO设备效率的功能,可以解决数据粒度不匹配问题,可以提高CPU与IO设备的并行性

image-20230823025522262

缓冲有多种策略,我们下面一一介绍,首先如果采用单缓冲策略,操作系统会在主存中为其分配一个缓冲区,一般其大小是一个块,这里值得一提的是当缓冲区数据非空时只能将缓冲区中的数据传出,而当其为空时,则可以往里传入数据,但是必须传慢之后才能把缓冲区的数据从中传出

image-20230823025716148

一般这种缓存区类型的都喜欢出题目计算每处理一块数据平均需要多久,我们这里的解题方法是假定一个操作系统的初始状态,然后分析到达相同状态需要运行多少时间,此时要画基于时间的坐标图

如下图所示,我们先设定每个时间处理需要的时间变量,然后假设输入时间T大于处理时间C,那么画图可知,回到最初的状态需要经历T+M的时间

image-20230823025924774

而当T<C时,分析可知平均用时为C+M,那么可以得到采用单缓冲策略处理一块数据平均耗时Max(C,T)+M

image-20230823030050353

当采用双缓冲策略时,操作系统会在贮存中为其分配两个缓冲区,同样我们假设一个初始状态,这里是工作区空,其中一个缓冲区慢,另一个缓冲区空的情况,先假设T>C+M,画图分析可知此时处理一块数据的平均用时为T

image-20230823030215991

然而当反过来时,我们画图分析就没这么容易了,因为不容易找到一个重新回到初始状态的确定区间值,那么此时我们可以把图继续画长点分析,认真分析我们会发现,每次经历C+M个时间后,T都会运行,那么就说明平均每处理一个数据块的平均耗时为C+M

image-20230823030524274

那么最终结论是采用双缓冲策略处理一个数据库的平均耗时为Max(T,C+M)

image-20230823030739629

当两台机器之间通信时,可以配置缓冲区用于数据的发送和接收,我们这里就在两个主机里采用了单缓冲策略,然而这种策略只能实现半双工传输

image-20230823030909296

我们可以在两台主机上采用双缓冲策略来实现全双工传输

image-20230823031119435

还有一种缓存策略是循环缓存策略,其会将多个大小相等的缓冲区连接成一个循环队列,其中in指针指向下一个可以冲入数据的空缓冲区,而out指针指向下一个可以取出数据的满缓冲区

image-20230823031209440

而缓冲池则是由系统中共用的缓冲区组成,按使用状态可以分为空缓冲队列、装满输入数据的缓冲队列(简称输入队列)、装满输出数据的缓冲队列(简称输出队列),而在缓冲池中设置了四种缓冲区,分别是用于收容输入数据的工作缓冲区hin、用于提取输入数据的工作缓冲区sin、用于收容输出数据的工作缓冲区hout、用于提取数据的工作缓冲区sout

当然,光说就太抽象了,我们来举个例子吧,如下图所示,在第一个步骤中会取出空缓冲队列中的队头缓冲区放入hin中用于输入数据,当其被充满后会被挂载到输入队列的队尾,第二步会从输入队列中取出一个缓冲区放入sin中用于取出数据,并且在取出完毕后会将该缓冲区挂载到空缓冲队列的队尾上,第三步会从空缓冲队列中取出一个空缓冲区放入到hout中用于接收进程准备好的数据并且会将其挂载到输出队列的队尾上,第四步会从输出队列中取出队头放入到sout中用于取出数据并会将该缓冲区挂载到空缓冲队列的队尾上

image-20230823031410068

最后我们来看看总结

image-20230823031428444

磁盘结构

本节我们继续来学习磁盘,磁盘也是一种IO设备

image-20230823033837077

磁盘分为磁道和扇区,磁道就是盘面的一个个圈,而扇区就是直接按照角度划分的一个区域(这其实就是磁盘块),这里值得一提的是每个扇区存储的数据量都是一样的,那么每个磁道和扇区存储的数据量都是一样的,由于圆的外圈周长大于内圈,因此最里面磁道的扇区存放的数据最为密集

image-20230823034005786

读取数据时需要将磁头移动到想要读写的扇区所在的磁道,磁盘会转起来,让目标扇区从磁头下面划过来完成数据的读写

image-20230823034109342

注意实际的磁盘一个盘片可能会有多个盘面,同时磁头也会有多个,每个盘面都对于一个,所有的磁头都连接同一个磁臂,因此所有磁头只能一起同步移动,所有磁盘的相对位置相同的磁道形成柱面,那么我们就可以用柱面号、盘面号、扇区号来定位一个磁盘块,这其实就类似于三位坐标的xyz,很好理解

image-20230823034357776

根据磁头是否可以移动可以将自盘分为活动头磁盘和固定头磁盘,前者的磁臂可以来回伸缩带动磁头定位,后者不可伸缩但每个磁道都对于一个磁头,要哪个磁道的数据直接激活对应的磁头即可

image-20230823034455996

根据盘片是否可以更换可以将磁盘分为可换盘磁盘和固定盘磁盘

image-20230823034544436

最后我们来看看总结

image-20230823034603667

磁盘调度算法

本节我们重点来讲磁盘调度算法

image-20230823035322264

一次磁盘读写操作需要的时间分为寻找时间、延迟时间、传输时间,假设寻找时间为Ts,那么其还可以细分为启动磁臂的时间s和移动磁头的时间mn,其中m为跨越一个磁道的耗时,n为一次读取需要跨越的磁道,假设延迟时间为Tr,假设磁盘转速为r,那么Tr=(1/2)(1/r)=1/2r,其中由于磁盘转速为r,因此1/r为磁盘转一圈所需的时间,由于找到目标扇区平均要转半圈,因此要令其乘以1/2,最后设传输时间为Tt,磁盘转速为r,此次读写的字节数为b,每个磁道的字节为N,那么Tt=(1/r)*(b/N)=b/rN,其中r/1是转盘转一圈的时间,b/N是一个磁道上持有的字节数,由于读写一个磁道平均是转一圈磁道的时间,所以1/r就为读取时间

我们这里通过观察不难发现,延迟时间和传输时间都和磁盘转速有关,而转速是硬件的属性,这个是不可能通过算法改变的,因此我们主要的优化是寻道时间

image-20230823040036611

通过磁盘调度算法,可以有效降低寻道时间,第一个磁盘调度算法是先来先服务(FCFS)算法,其算法逻辑非常简单,先来的请求先服务,其缺点是可能会出现性能极差的情况

image-20230823040208019

而最短寻找时间(SSTF)算法,其核心是贪心算法,每次总是会选择离当前磁头最近的磁道来执行,其优点是性能较好,缺点是可能会出现饥饿现象

image-20230823040504243

为了解决饥饿现象,发明了扫描(SCAN)算法,其逻辑是只有磁头移动到最外侧磁道时才能往内移动,移动到最内侧磁道时才能往外移动,由于其运行逻辑很像电梯,因此也叫电梯算法,这里可以看到即使到达了184,后面已经没有响应的磁道了,其仍然会移动到200之后再转向扫描

该算法的优点是性能较好,不会产生饥饿,缺点是性能还有优化空间而且对各个位置的磁道响应频率不平均,简单来说就是有的位置响应快,有的响应慢

image-20230823040724463

为了解决扫描算法的效率问题,产生了LOOK调度算法,其运行逻辑是如果移动方向上没有别的请求,就可以立刻改变磁头方向,因为感觉起来像是边移动边观察,因此得名为LOOK算法,其可以进一步缩短寻道时间

image-20230823040839613

而为了解决扫描算法的响应频率问题,产生了C-SCAN算法,其逻辑时只有磁头朝某个特定方向移动时才处理磁道访问请求,而返回时直接返回到起始端,不做任何请求的处理

这个算法的好处是各个位置的磁道响应频率很平静,缺点是性能比SCAN还烂

image-20230823041028189

C-LOOK算法为了解决C-SCAN算法效率不高的问题,其将运行逻辑改进为党磁头移动的方向上没有请求时,就直接转向,其好处是效率比C-SCAN算法的效率高

image-20230823041124386

最后我们来看看总结

image-20230823041150136

减少延迟时间的方法

实际的磁盘读入数据里,磁头在读入一块数据后,还需要一小段时间处理,这个时间可以简单认为是读取一个扇区所需的时间,如果我们的扇区是相邻排列的,那么当我们要读写连续的扇区时,会徒增不必要的因为盘片旋转引起的延迟时间的增加

image-20230823043229208

解决这个问题可以采用交替编号的策略,让相邻的扇区在物理上有一定间隔,这样读取连续的扇区时可以正好让处理时间在处于不需要读取的扇区中,这样可以有效防止延迟时间的增加

image-20230823043428144

为什么磁盘的物理地址是(柱面号,盘面号,扇区号)而不是(盘面号,柱面号,扇区号)?这看似是个弱智问题,其实里面还真大有学问,我们先来看看后者的案例,可以看到,在后者的案例里需要需要启动磁臂将磁头转移到下一个磁道

image-20230823043641197

而在前者的案例中,则不需要移动磁臂,直接激活相邻盘面的磁头就行了

image-20230823043746079

那么采取前者的地址结构的原因是可以减少磁头移动消耗的时间

image-20230823043813589

同时如果相邻的盘面的扇区编号完全相同,可能会出现延迟时间增大的情况

image-20230823044014198

因此同样可以采取错位命名不同盘片的扇区来防止延迟时间增大的情况

image-20230823044157940

最后我们来看看总结

image-20230823044217380

磁盘管理

磁盘的管理分为磁盘初始化、引导块和坏块管理

image-20230823045226736

磁盘初始化首先会进行低级格式化,也称低级格式化,其会将各个磁道划分为扇区,一个扇区可分为头、数据区域、尾三个部分,其中数据区域用于存放数据且每个扇区可存放的数据是一致的,尾一般存放指向下一个扇区的指针,而头则存放扇区校验码等内容

第二步会将磁盘分区,其实就是分为我们熟悉的CDE盘

第三步会进行逻辑格式化,会创建文件系统。

image-20230823045443432

计算机开机时需要进行一系列初始化工作,这些工作时通过执行初始化程序,也就是自举程序执行的,自举程序一般存放到ROM中,ROM的数据在出厂时就写入了且以后不能修改,此时存在的问题就是以后更新自举程序很不方便,毕竟这个程序放到了ROM中

image-20230823050307413

为了解决该问题,现在ROM中都只存放很小的自举装入程序,而完整的自举程序放在磁盘的启动快,也就是引导块/启动分区上,启动块位于磁盘的固定位置,这样更新的时候就直接更新启动磁盘上的完整的自举程序就完了,非常方便

一般来说,拥有启动分区的磁盘称为启动磁盘或系统磁盘

image-20230823045741427

坏块指的是无法正常使用的扇区,其属于硬件故障,操作系统无法修复,只能避免使用。

对于简单的磁盘,在逻辑格式化时会对整个磁盘进行坏块检查,标明哪些扇区时坏的,从而达到避免使用的效果,而对于复杂的磁盘,其内部的磁盘控制器会维护一个坏快链表,同时在出厂前进行低级格式化时就将坏块进行初始化,还会保留一些备用扇区用于替换坏块,这种方法称为扇区备用,这种处理方式对于操作系统来说是透明的,不可知的

image-20230823045933699

最后我们来看看总结

image-20230823045955074

固态硬盘SSD

本节我们来讲固态硬盘SSD的原理

image-20230823051021361

首先固态硬盘德源里是基于闪存(Flash Memory)技术的,属于电科擦除ROM,即EEPROM,内部有多个闪存芯片,比如下图中就能看到很多芯片

image-20230823051058805

其结构如下图所示,数据要进行读写时首先进入闪存翻译层,该层负责翻译将逻辑块号的地址映射到对于的物理地址(其内部保存了逻辑块号到对于页号的映射),而闪存芯片组中有多个闪存芯片,每个芯片包含多个块(block),每个块包含多个页(page),注意固态硬盘是以页为单位的,所以闪存翻译层也是负责找到对应的页

我们可以简单理解为其中的块就是磁道,而页就是扇区,当然不能真的这么认为,方便理解而已,固态硬盘中支持以页进行读写和以块为单位进行擦除,其中每页都可以写一次和读无数次,也就是说如果要在一个块中的页里重新写入,那么就要将该块先擦除再写入,当然块中会有其他数据,这些数据会被迁移到另一个已经擦除完的块中存放,同时会更改闪存翻译层保存的映射,由于这种特性,因此固态硬盘读的速度远远快于写,毕竟写还可能要擦除,但读肯定是不会的

其支持随机访问,系统给定一个逻辑地址,闪存翻译层就可以通过电路迅速定位物理地址,比移动硬盘快得多得多

image-20230823051237984

固态硬盘存在一个问题就是可能会因为一个块被擦除的次数过多导致损坏,为了防止这种情况,其引入了磨损均衡技术,细分为动态磨损均衡和静态磨损均衡,前者是写入数据时优先选择累计擦除次数少的闪存块,后组合指的是SSD检测并自动进行数据的分配和便宜,令老旧的内存块更多承担读数据而非写数据,令新闪存块承担写数据

当然,固态硬盘的寿命短也是跟机械硬盘比的,普通家用电脑你基本上是不可能把固态硬盘用坏的

image-20230823051839992