《操作系统导论》读后感

完稿于

一、写在前面

花了不到一个月的时间,粗略地读完了《操作系统导论》(原名:Operating Systems Three Easy Pieces;又名ostep),还是有所收获和感悟的。由于个人的时间与精力有限,无法做详细的整理,所以以读后感的形式来为这段读书经历作结。有意思的是,这应该是我第一篇自愿写的读后感。

二、ostep简介

所谓Three Easy Pieces就是指:本书围绕虚拟化、并发以及持久性三个主要概念展开,介绍了现代操作系统的主要组件。下面我也围绕这三点略作介绍。

1)虚拟化

虚拟化可以分为两方面——CPU的虚拟化、内存的虚拟化。

先谈CPU的虚拟化

CPU虚拟化可理解为:CPU按照某种调度方案在多个进程之间上下文切换,使得进程认为自己独占了整个CPU。在学习CPU虚拟化时,先是学习了一些进程API——如何利用fork()创建子进程、wait()回收等待进程以及exec()运行程序,然后讨论了多种调度方案——先进先出(FIFO)、最短任务优先(SJF)、最短完成时间优先(STCF)、多级反馈队列(MLFQ)、彩票(ticket)等等。

再谈内存虚拟化

内存虚拟化可以理解为:通过虚拟地址空间让程序以为自己独占了整个内存。稍微具体来说,一个C程序的栈、堆、全局变量区的虚拟地址都是有固定范围的,而这些虚拟内存地址通过映射到的物理内存地址则是杂乱无章的。虚拟地址的引入具有很多优势,包括简化了链接、加载、共享等诸多方面,这里也不详细讨论了。

在学习内存虚拟化时,其实就是在学习如何把虚拟地址翻译到物理地址。我们学习了页表TLB,简单来说访问物理地址过程如下:先利用虚拟地址到TLB中找表项,未命中就到内存中把该页表弄到TLB中,再次到TLB中寻找表项便可命中;通过表项把虚拟内存翻译为物理内存,再通过物理内存在内存中找到目标数据;对于不在内存里的页,通过页错误,到磁盘中把数据传送到内存中。

2)并发

进程之间是不共享地址空间的,也就不共享数据。这时我们引入一个全新的抽象叫做线程,不同的线程之间可以共享数据,多个线程共同协作来完成一件事情,这样我们就实现了并发。学习并发主要就是学习锁和条件变量的实现和使用。保证了临界区(访问共享资源的一段代码)最多允许一个线程进入,避免了多个线程同时访问同一个共享变量造成的难以理解的bug。我们学习了锁的api以及背后可行的硬件原语的支持。我们还实现了一些线程安全的并发数据结构——并发计数器、并发列表、并发队列和并发散列表。条件变量则允许父线程检查子线程执行完毕。我们同样也学习了条件变量的api,并利用条件变量和锁讨论了生产者/消费者问题以及与之类似的读者—写者锁。最后我们学习了信号量这一全新的实现方案,并利用信号量实现了锁以及条件变量,而不是调用锁以及条件变量的api。最后的最后本章又探讨了基于事件的并发,但是没有看懂,似乎之前的并发都是基于线程。

3)持久性

何为持久性?我们之前讨论的数据都是存在内存之中,但是内存中的数据都是在断电后会失去的,而要做到持久就要把数据存在磁盘中。说白了,讨论持久性就是讨论磁盘的结构。本章先是介绍了磁盘的物理结构——盘片、磁道、扇区等等,再利用多个磁盘来设计廉价冗余磁盘阵列(RAID,redundant array of inexpensive disk)——一种更快、更大、更可靠的磁盘系统,应该就是机房里插了许多磁盘的大家伙了,而什么RAID 0、1、4、5级这里就不展开了。

然后本章着重介绍了文件系统。存储虚拟化有两个关键的抽象:第一个是文件,文件是一个线性字节数组,拥有一个低级名称,通常是一个数字叫做inode号;第二个是目录,目录包含一个inode号外还有一个可读名字,如("foo", "10")对。而管理文件和目录以及各种崩溃的系统便是文件系统。本章介绍了多种文件系统思路——简单文件系统(VSFS,应该是作者自创)、快速文件系统(FFS)以及日志结构文件系统(LFS)。取其共性来说,我们把文件数据和元数据(元数据:大小、创建日期、数据块的位置信息等等所有关于文件的信息)分开,文件数据存在文件块中,元数据存在inode块中。

举个例子。调用open("/foo/bar", O_RDONLY),大体思路为:已知根目录“/"的inode号,利用该inode号找到inode块,在该inode块中查找指向数据块的指针并以此找到数据块,数据块中包含根目录的内容,在目录中找到foo条目以及它的inode号,利用foo的inode号找到inode块,inode块中的指针找到目录数据块,在数据块找到bar的inode号,最后把bar的inode号读入内存并返回一个文件描述符。此外文件系统还需记录inode块和数据块是否空闲(可利用位图)。

快速文件系统利用分组倾向于把相关的东西放在一起,从而避免了大量磁盘寻道。所谓相关的东西包括:同一目录下的文件、inode块和相应的数据块。日志结构文件系统不再规定inode块、数据块、超级块和位图位置的具体范围,而是通过把数据缓存在内存,然后一口气大量顺序写入磁盘,以提高性能。然而伴随日志结构文件系统产生的垃圾收集和崩溃恢复问题则相当的棘手,本人也不明就里,不做展开。

在介绍文件系统的时候,还介绍了崩溃一致性问题。就是在写入时突然崩溃(比如,突然断电而导致了崩溃)如何保证位图和inode块一致等问题。比如说,数据位图已经更新为占用,然而inode块却没有写入,也就没有指针指向这个数据块,这会导致该数据块永远不会再次被分配(一种空间泄露)。主要讨论了两个解决方法——文件系统检查程序fsck、日志。fsck就是在不断遍历检查各种信息,完全就是在扫描整个磁盘,肉眼可见的慢。日志则是ext3、ext4等诸多文件系统都采用的,稍微再讲一下元数据日志的一些思路。(1)我们先把数据写到最终位置以及把事物开始块和元数据写入日志(日志也在磁盘上);(2)完成上述步骤后再把事物结束块(事物提交块?鬼知道确切什么名字)写入到日志,写入完成后认为事物已经提交;(3)把好多日志写入磁盘中的最终位置,此步骤名为加检查点元数据;(4)在日志超级块中把事务标记为空闲。此外数据日志,把数据也写入日志了,这样会产生两次磁盘写入,造成时间的浪费。

最后介绍了分布式系统,分布式系统大概就是若干独立计算机的集合,这计算机集合对用户来说就像单个相关系统。似乎就是在讨论计算机之间如何进行通讯以及在组件故障时保证系统的正常工作。并没有看懂、也看不进去。。。

三、我的感悟

值得一读

个人认为,ostep是一部值得读的操作系统入门方面的书籍。首先ostep通过一些愚蠢的玩笑话做到了语言方面的轻松不拗口。在专业知识方面,ostep对新概念的引入以及展开的深度都做的不错。个人在读虚拟化以及并发两大板块的时候,绝大部分都相当顺畅!可能虚拟化我在csapp中仔细读过,并发受虚拟化的惯性影响读的比较开心(csapp自己其实没有看第十二章的并发)。但是在看持久性的时候还是遇到了困难,可能这块内容完完全全是新的吧。不过书中讨论的持久性完全是在磁盘的基础上,SSD并没有什么涉及,我觉得这是本书所缺失的一块内容。但是,瑕不掩瑜!想要建立有关虚拟化、并发以及持久性感性乃至理性认知的话,ostep是一部很不错的书籍。

与csapp比较

csapp是一部类似百科全书一样的书籍,ostep中的虚拟化以及并发两大板块是几乎囊括其中的,不过csapp并没有怎么讲述调度方案等细节。不过持久性板块的内容,csapp应该是完全没有涉及的,这也可能一定程度导致我一开始看文件系统时一脸懵的状态。其实我看csapp是相当吃力的,一方面是可能自己看的是英文版,另一方面许许多多的新概念我并不能立刻接受。

接下来

自从暑假扫完csapp以及现在扫完ostep后,其实我是没有写什么代码的,很多东西都是纸上谈兵而没有什么写码能力。不过这也合理,先理解基本概念,再在运用中更好的掌握它,这样之后才能做更进一步的学习。计划这个学期抽一点时间要做一些csapp的lab,至于其它的那些书籍,什么计算机组成以及体系结构方面的书,不计划在这学期看。

学习新知识大概如此吧,首先找本好书并没有读的很懂;然后再换本好书(当然刚刚的书也行)读到完全的感性认知,认为这些设计不是显然的吗,可以和人复述;这样之后再去不断地实战练习,巩固自己的记忆;最后可能会找到新的问题、新的方向,再去探寻更广阔的知识海洋。(莫名奇妙的结尾升华部分)