操作系统之哲学原理

​ 这本书以人类自我管理的角度,来看待操作系统的几个核心功能。操作系统是人造的,所以很多设计都借鉴了人类在长期的生活实践中摸索出来的管理社会和保障自身安全的各种办法。

​ 另一个不得不接受的事实是,因为操作系统是人造的,它远不完美。数学力求精确,而软件却没有任何精确可言,是十足的“差不多”学科。因为软件是一门人造学科,它没有对与错(这里指的是同一功能的不同实现,而不是说程序不可能出现错误),只有好或坏。我们设计软件的时候,也是觉得差不多就可以了,而没有什么精确的追求。纵观全书,操作系统各功能的设计改进过程,随时要做出不得已的折中和妥协。

​ 这本书是学习操作系统一个很好的入门之选。要了解操作系统更深入的细节,还要阅读和实践更多的东西。

一.几个核心概念:

  • 内核态和用户态:*

    所谓的用户态、内核态实际上是处理器的一种状态,而不是程序的状态。我们通过设置该状态字,可以将CPU设置为内核态、用户态或者其他的子态(有的CPU有更多种子态)。一个程序运行时,CPU是什么态,这个程序就运行在什么态。状态不同意味着权限和拥有的资源不同。

  • 系统调用:

    操作系统是一个系统程序,即为别的程序提供服务的程序。那么操作系统的服务是通过什么方式提供的呢?答案是系统调用(system call)。

​ 系统调用分为三个阶段,分别是:

  1. 参数准备阶段。
  2. 系统调用识别阶段。
  3. 系统调用执行阶段。
  • 壳:

    用户程序通过调用操作系统提供的系统调用API来获得操作系统的各种服务。但使用API需要编程。为了向这些不编程的用户提供服务,操作系统提供了一个壳(shell)来与用户交互。每个操作系统都提供某种壳,以便与用户进行交互。这个壳是覆盖在操作系统服务上面的一个用户界面,既可以是图形界面,也可以是文本界面。用户在这个界面上输入命令,操作系统则执行这些命令。

二.进程核心概念

当人们面临困境时通常的做法就是:发明新的概念、新的术语或新的机制来解脱困境。进程亦是如此。

  • 1.什么是进程?

​ 顾名思义,进程就是进展中的程序,或者说进程是执行中的程序。就是说,一个程序加载到内存后就变为进程。即:

​ 进程=程序+执行

进程在Multics操作系统出现前叫做工作(job)工作是IBM用于多道批处理程序设计中的概念。由于历史的原因,Multics操作系统的研发人员不愿意承用IBM发明的术语,所以称为进程。

  • 2.进程有什么用?

​ 20世纪40年代,计算机使用的还是单一操作员单一控制终端系统。单一操作员单一控制终端、批处理均存在效率低下的问题,即CPU使用率不高。为了提高CPU利用率,人们想起将多个程序同时加载到计算机里,并发执行。这些同时存在于计算机内存的程序就称为进程。进程让每个用户感觉到自己独占CPU。因此,进程就是为了在CPU上实现多道编程而出现的概念

  • 3.进程模型

[外链图片转存失败(img-jdFiTm5L-1564194055679)(C:\Users\Administrator\Documents\Tencent Files\1364584631\FileRecv\MobileFile\save_share_review_picture_1563751809.jpeg)]

三个视角看进程模型

​ 要实现逻辑上的并发,就要对cpu进行切换。操作系统解决这个问题的手段就是进程调度:决定在什么时候让什么进程使用CPU。

[外链图片转存失败(img-4p4cKtkf-1564194055683)(C:\Users\Administrator\Documents\Tencent Files\1364584631\FileRecv\MobileFile\save_share_review_picture_1563752108.jpeg)]

随着进程数量的增加,也就是随着多道编程的度的增加,CPU利用率将逐步提升,但提升的幅度则逐步降低,直到某个临界点时为止。

  • 4.进程的产生和销毁:

    对于进程产生来说,主要的事件有:

    1.系统初始化(神创造人)。

    2.执行进程创立程序(人生子)。

    3.用户请求创立新进程(试管婴儿)。

​ 造成进程消亡的事件则可以分为四种情况:

​ 1.寿终:进程运行完成而退出。

​ 2.自杀:进程因错误而自行退出。

​ 3.他杀:进程被其他进程所终止。

​ 4.处决:进程因异常而被强行终结。

​ 前两种情况均为自愿退出,后两种情况均为非自愿退出。

  • 5.进程层次结构:

    ​ 一个进程在执行过程中可以通过系统调用创建新的进程。这个新创建的进程就称为子进程,而创建子进程的进程则称为父进程。子进程又可以再创建子进程,这样子子孙孙创建下去就形成了所谓的进程树。

  • 6.进程的状态:

    进程分为3种状态:执行、阻塞和就绪。

[外链图片转存失败(img-N9ClqtR2-1564194055684)(C:\Users\Administrator\Documents\Tencent Files\1364584631\FileRecv\MobileFile\save_share_review_picture_1563752557.jpeg)]

在3种状态之间可以进行各种转换。如果每个状态都可以转换为另外一种状态,则一共有6种转换:

​ 执行→就绪

​ 执行→阻塞

​ 阻塞→就绪

​ 就绪→执行

​ 阻塞→执行

​ 就绪→阻塞

这里阐述的进程的3种典型状态并不是唯一的分类方式。事实上,许多商业操作系统的进程状态不止3个,例如,Windows的进程有7个状态,Solaris的进程则有6个状态。但不管3个、6个、7个还是几个,其目的都是便于操作系统管理进程。

小结:

地址空间就是进程要用的所有资源,好比舞台和道具,进程就是演员,操作系统就是导演。每跳上来一个演员,操作系统要记录维护的资料信息应当包括寄存器、程序计数器、状态字、栈指针、优先级、进程ID、信号、创建时间、所耗CPU时间、当前持有的各种句柄等。进程管理的最大问题是资源分配.。公平与效率就成了进程管理中永恒的主题。

进程的调度

  • 调度的目的:

    CPU调度就是要达到极小化平均响应时间、极大化系统吞吐率、保持系统各个功能部件均处于繁忙状态和提供某种貌似公平的机制。

  • 调度算法种类:

    1.先来先服务调度算法FCFS

    2.时间片轮转算法

    3.短任务优先算法

    4.优先级调度算法

    5.混合调度算法

    6.其他调度算法:

    保证调度(Guaranteed Scheduling)、彩票调度(Lottery Scheduling)、用户公平调度(Fair Share Scheduling Per User)。

    7.实时调度算法:

    比如,计算来袭导弹轨迹的进程,其计算时间是非常有限的。如果该进程不能在规定时间内计算出来袭导弹的轨迹,则结果毫无意义。

    8.EDF调度算法:

    EDF调度算法就是最早截止的任务先做。EDF算法是一种动态调度算法。

    9.RMS调度算法:

    与EDF算法相对的是所谓的RMS调度算法。该算法在进行调度前先计算出所有任务的优先级,然后按照计算出来的优先级进行调度,任务执行中间既不接收新的进程,也不进行优先级的调整或进行CPU抢占

  • 进程调度执行过程:

    首先先,需要将当前进程的状态予以保护,以便将来能够重新执行。然后是将选中的进程的环境布置好,这包括设置寄存器、栈指针、状态字等操作。最后是跳转到选中的进程,也就是设置或恢复其程序计数器

  • 优先级倒挂:

    指的是一个低优先级任务持有一个被高优先级认为所需要的共享资源。这样高优先级任务因资源缺乏而处于受阻状态,一直到低优先级任务释放资源为止。这样实际上造成了这两个任务的优先级倒挂。如果此时有其他优先级介于二者之间的任务,并且其不需要这个共享资源,则该中级优先级的进程将获得CPU控制,从而超越这两个任务,导致高优先级进程被临界区外的低优先级进程阻塞。

进程通信的手段:

  • 1.管道:

    管道是一个线性字节数组,类似文件,可以使用文件读写的方式进行访问。但却不是文件。因为通过文件系统看不到管道的存在。

    壳(shell)命令行下,只需要使用符号“|”即可。

ps -ef|grep java  

​ 在程序里面,创建管道需要使用系统调用popen()或者pipe()。popen()需要提供一个目 标进程作为参数,然后在调用该函数的进程和给出的目标进程之间创建一个管道。这很像人们打 电话时必须提供对方的号码,才能创建连接一样。

  • 2.记名管道:

    如果要在两个不相关的进程(如两不同进程里面的进程)之间进行管道通信,则需要使用记名管道。顾名思义,命名管道是一个有名字的通信管道。一个进程创建一个记名管道后,另外一个进程可使用open来打开这个管道(无名管道则不能使用open操作),从而与另外一端进行交流。

  • 3.套接字:

    套接字首先在BSD操作系统中出现,随后几乎渗透到所有主流操作系统中。套接字的功能非常强大,可以支持不同层面、不同应用、跨网络的通信。使用套接字进行通信需要双方均创建一个套接字,其中一方作为服务器方,另外一方作为客户方

  • 4.信号:

    那么信号是什么呢?在计算机里,信号就是一个内核对象,或者说是一个内核数据结构。发送方将该数据结构的内容填好,并指明该信号的目标进程后,发出特定的软件中断。操作系统接收到特定的中断请求后,知道是有进程要发送信号,于是到特定的内核数据结构里查找信号接收方,并进行通知。接到通知的进程则对信号进行相应处理。类似生活中的电报。

  • 5.信号量:

    在计算机里,信号量实际上就是一个简单整数。一个进程在信号变为0或者1的情况下推进,并且将信号变为1或0来防止别的进程推进。当进程完成任务后,则将信号再改变为0或1,从而允许其他进程执行。

    需要注意的是,信号量不只是一种通信机制,更是一种同步机制。

  • 5.共享内存:

[外链图片转存失败(img-XRTkCeE1-1564194055685)(C:\Users\Administrator\Documents\Tencent Files\1364584631\FileRecv\MobileFile\save_share_review_picture_1564186190.jpeg)]

​ 享内存就是两个进程共同拥有同一片内存。对于这片内存中的任何内容,二者均可以访问。要使 用共享内存进行通信,一个进程首先需要创建一片内存空间专门作为通信用,而其他进程则将该 片内存映射到自己的(虚拟)地址空间。这样,读写自己地址空间中对应共享内存的区域时,就 是在和其他进程进行通信。

  • 6.消息队列:

    它无需固定的读写进程,任何进程都可以读写即所谓的多对多,而不是管道的点对点。另外,消息队列只在内存中实现。

  • 7.其他通信机制: 例如windows的剪切板。

小结:

虽然进程之间的通信机制繁多,且每种机制都有着自己的特性,但归根结底都来源于AT&T的UNIX V系统。该系统在1983年加入了对共享内存、信号量和消息队列的支持。而这三者就是众所周知的System V IPC(POSIX IPC也是源于该系统并成为当前IPC的标准)。因此,虽然不同操作系统的IPC机制可能不尽相同,但其基本原理则并无大的区别.

线程

​ 虽然进程和进程出现的动机都是并发,但它们的并发层次不同:进程属于处理器级并发,即在处理器这一层次上提供并发的抽象;线程则属于进程级并发,即在进程这个层次上再提供一层并发的抽象。如果我们下到底层,进入计算机体系结构里就会发现,流水线提供的也是一种并发,不过是指令级并发。这样,流水线、进程、线程就从低到高在3个层次上提供我们所迫切需要的并发!

​ 将进程分解为线程还可以有效地利用多处理器和多核计算机。在没有线程的情况下,增加一个处理器并不能提高一个进程的执行速度。但如果分解为多个线程,则可以让不同的线程同时运转在不同的处理器上,从而提高了进程的执行速度。

​ 线程模型有用户态实现和内核态实现。用户态需要编程。

​ 线程中比较重要的概念:

  • 1.同步

  • 2.锁

管程:

​ 管程的英文单词是monitor,即监视器的意思。它监视的就是进程或线程的同步操作。管程是一个程序语言级别的构造,即它的正确运行由编译器负责保证。这就是计算机里面的一条哲学原理:你不行的时候,把困难交给别人。

​ 具体来说,管程就是一组子程序、变量和数据结构的组合。言下之意,把需要同步的代码用一个管程的构造框起来,即将需要保护的代码置于beginmonitor和end monitor之间,即可获得同步保护。在任何时候只能有一个线程活跃在管程里面。那谁来保证这一点呢?编译器。编译器在看到begin monitor和end monitor时知道其间的代码需要同步保护,在翻译成低级代码时就会将需要的操作系统原语添上,使得两个线程不能同时活跃于同一个管程内。

​ 在管程里面使用两种同步机制:锁用来互斥,条件变量用来控制执行的顺序。从某种意义上说,管程就是锁加上条件变量。

​ 管程的中心思想是运行一个在管程里面睡觉的线程。但是在睡觉前需要把进入管程的锁或信号量释放,否则在其睡觉后别的线程将无法进入管程,就会造成死锁。

栅栏:

栅栏就是一个障碍。到达栅栏的线程必须停止下来,直到除去栅栏后才能往前推进

死锁:

如果有一组线程,每个线程都在等待一个事件的发生,而这个事件只能由该组线程里面的另一线程发出,则称这组线程发生了死锁。

死锁的4个必要条件:

  • 1.资源有限

  • 2.持有等待:

    如果不是这样,死锁也不能发生。因为一个线程在请求资源时,其并没有持有任何资源,自然就不会阻挠别的线程运行。

  • 3.不能枪占

  • 4.循环等待:

    这是死锁的最后一个条件。如果你等我、我等你,大家都这样等着对方,就产生了死锁。

死锁的解决方案:

  • 1.不予理睬:

    而我们研究商业操作系统的人不认为这是什么大问题,因为经过分析发现,死锁发生的频率不太高(当然这点有争议),所以不必管它。另外,防止死锁的代价很高,防止死锁比重启100次代价还高,因此不如直接重启。如果死锁发生,重启即可。这就是为什么Windows、Linux和其他商业操作系统都没有采取死锁防止措施,这就是为什么你的电脑经常死机的原因。对于一些必须避免死锁的程序,则需要进行处理。

  • 2.检测和修复

  • 3.动态避免

  • 4.静态防止

小结:

​ 在应对死锁的策略上,我们讲解了4种策略:静态防止、动态避免、不予理睬和检测修复。用人口控制来作比喻,就是不控制婴儿的出生;允许生育,但想办法处理出生的婴儿;不准结婚来静态防止生育和可以结婚但不许生育来进行动态避免。

内存:

内存管理要达到如下两个目标:

  • 1.地址保护:一个程序不能访问另一个程序地址空间。

  • 2.地址独立:程序发出的地址应与物理主存地址无关。

内存管理方法:

1.固定加载地址的内存管理

2.固定分区的内存管理

3.非固定分区的内存管理

4.交换内存管理。

以上方式会产生很多闲置的空间,这种散布在进程之间的闲置空间称为外部碎片。为此出现了分页系统。

5 .分页系统

分页系统的核心就是将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里。

小节:

表太大?这个缺点用多级页表克服了。多级页表速度慢?这个问题用TLB解决了绝大部分。页面来回更换?这个缺点用页面更换算法解决了大部分。固定页面大小呢?这不应该算是一个缺点,因为可变页面大小的操作系统不仅难以选择最优的页面大小,而且会变得很复杂。

文件系统:

简单地说,文件系统将其接触的磁盘物理特性转换为用户看到的路径名和文件名。用户对磁盘进行访问只需要给出文件名和路径名即可,而无须知道磁柱、磁道、扇面、数据块等信息

总结:

《操作系统之哲学原理》一书是学习操作系统入门的不错选择,很多复杂抽象的概念,用人类生活中的场景加以对比说明,很容易理解。但是要学习操作系统更细节的实现,这还仅仅是个开端。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值