目录
操作系统概述
操作系统中的抽象概念
准备知识
中断输入输出
软件中断
处理器特权级
操作系统的结构
程序的结构
运行时视图简介
可执行文件
编译器、汇编器、连接器、调试器与解释器程序
直接回填法和间接地址法
过程(子程序)结构
从运行时库到运行时环境
静态链接库和动态链接库
线程与时间
指令流间的执行顺序
指令流的三个基本状态
线程的描述⭐️
线程控制块(TCB)
指令流 VS 线程
线程的调度算法
固定优先级调度算法⭐️⭐️
调度策略——保证公正(公平+正义)⭐️⭐️⭐️
复杂系统的调度:按线程行为分类
广义的调度算法
系统中的线程总览:按特权划分
线程的基本操作
进程与主存空间
程序内的分配策略⭐️
固定分区法
首次适配法(First-Fit)
最好适配法(Best-Fit)
最坏适配法(Worst-Fit)
进程的描述
进程控制块(PCB)
进程与可执行文件
线程与进程⭐️
内存隔离机制:分段
内存隔离机制:分页
请求分页,替换算法⭐️⭐️⭐️
最长前向距离算法(LFD)
先进先出(FIFO)
最久未用法(LRU)
Belady异常
Linux页面替换——二次机会法
页面置换的其它考量
进程的操作
概念梳理:
简单的设备——库结构(简要结构、单核结构)
通用的设备——宏内核结构
灵活的设备——微内核结构
高效的设备——外核结构
运行时视图:程序在执行时的主存储器布局,也叫运行时布局。
解释型语言的性能和编译型语言的性能哪个好?(AI回答)
- 编译型语言的性能通常比解释型语言好。
- 编译型语言是在程序运行之前将代码翻译成机器代码,这样程序在运行时可以直接执行机器代码,因此运行速度较快。
- 而解释型语言则是在程序运行时逐行翻译和执行,所以运行速度通常较慢。
- 当然,在某些情况下,解释型语言可能会更适用,比如需要频繁修改代码的场景,因为解释型语言不需要再次编译整个程序。
静态链接库
动态链接库
并发与并行
- 并行是并发的一种具体实现,在并行环境中,不仅并发程序的各个指令流的指令执行的先后顺序无法预测,而且这些指令流实现了真正的同时、一齐执行。
- 在单核处理器的并发环境中,无法实现并行,因为只有一个CPU,不可能同时执行多道程序,仅仅是交替执行多道程序让它们看上去在同时运行。
指令流:一个应用程序内部可以由一个或多个逻辑上相互独立执行的指令序列组成。这种独立执行的指令序列叫做指令流。CPU靠执行指令流来完成应用程序的功能。
指令流与时间:操作系统需要给指令流分配CPU时间,然后让这个指令流拿着这个CPU时间配额去运行。但是,指令流是用户程序的逻辑组成部分,操作系统并不知道用户程序里面有几条指令流。
线程(Thread)的概念
- 在应用程序看来,自己的逻辑组织是一系列并发执行的指令流。
- 在操作系统看来,应用系统的运行组织是一系列被分配了CPU时间的线程。
线程的描述——时间
线程的描述——优先级
- 关于上边提到的偏序集,举例说明:令A,B,C,D分别为四个独立运行的子系统,A可以抢占B(即有A>B)但不能抢占CD,C可以抢占D(即有C>D)但不能抢占AB,这也就是说A和CD实际上无法比较(已知A>B,C>D,但是不知道A和CD的关系)。
- 关于数据:指令流数据放在用户模式;线程数据放内核模式。
线程的描述——上下文
内核阻塞:
- 操作系统并不知道指令流的存在。因此,在遇到线程上的指令流陷入内核阻塞的时候,内核只能暂停执行当前这个线程,切换到别的线程去执行。
- 更麻烦的是,线程什么时候陷入内核,依附在线程上的指令流是不知道的,也即可能发生抢占。
- 一旦一个线程阻塞在内核,对它上面依附的所有指令流来说,时间就都凝固了。因此,这些指令流都停止运行。
线程的状态和指令流的状态是类似的,也包括运行、就绪和阻塞三个状态。(再放一遍图)
协程:
- 合作执行的一组指令流。
- 不仅强调它们不是时间分配的独立对象(区别于线程),而且强调只有其中某个指令流主动放弃CPU时,其他指令流才可以得到CPU进行运行,并且放弃CPU的那个指令流还倾向于指定谁来接替它的执行。
纤程:
- 合作执行的一组指令流。
- 相比于协程,放弃CPU的那个指令流不倾向于直接指定接替执行者,而倾向于唤起一个在用户空间的调度器,由它来决定下一个执行的指令流是谁。
- 纤程之间不一定有紧密的合作关系,仅仅是强调它们比线程要轻量,也即多个纤程共享一个线程。
同多于异,几乎是同义词,都是指令流,不过侧重点不同。
系统的响应:多个程序可能同时竞争CPU。它们都说自己最需要,然后也都可能就占着不放了。我们不能让某个应用程序霸占CPU,而是需要保证多个程序都能分到一部分CPU来运行自己,保证CPU的利用公正。
公平的常见调度
- 平均等待时间是机会公平,平均周转时间是结果公平;
- 平均等待时间只是等待时间,平均周转时间处理等待时间,还考虑运行时间以及决策等待时间。所以在一定程度上平均周转时间更加公平。
正义的常见调度
平均周转时间和响应时间相比有何区别?为何说前者体现了公平,后者体现的则是正义?
- 平均周转时间关心一切线程的运行时间,而响应时间仅仅关心那个用户刚刚提交的线程产生的第一个反馈。
- 前者关心所有线程,后者只关心某个线程,仅仅是因为那个线程是用户刚刚提交的,它的响应结果可能是用户正在等待的。
平均带权周转时间:计算式为(T1/R1+T2/R2+...+Tn/Rn)/N。T/R又叫响应比,T/R=1+(W/R)
对于同样的W,R越小,W/R越大;对于同样的R,W越大,W/R也越大。一个越短任务的等待时间越长,对这个指标越不利。
公平体现在该式包含了对所有任务的考虑。
正义体现在该式对越短任务的越长等待越不容忍。
公平的极端:先来先服务(FCFS)
正义的极端:短作业优先(SJF)
问题:如果在E3执行完成前,用户向系统中提交E4、E5、E6,这些任务所需要的执行时间都比E3短,那么意味着它们会一直插队到E3之前。那也就是说,用户一直提交短作业,那意味着E3将永远得不到执行了。
(这和FCFS的情况不同,对于FCFS,后到的作业一定后运行)
饥饿现象:依照某种资源分配策略,某些请求无限增加时,另一些请求将永远得不到分解。在CPU调度的问题上,它体现为某些线程将永远不能获得CPU。
响应比高优先(HRRN)
时间片轮转法(RR)
问题:前面提到的各种算法中,要么使用基于固定优先级的抢占(FP或SJF),要么就干脆排排坐吃果果。前者在复杂的场景会导致饥饿,从而可能导致系统卡死,后者则无法在一个任务开始执行后将其中途打断。接下来提到的时间片轮转法就是不产生饥饿,又能打断长任务以获得交互能力。
固定优先级时间片轮转法(FPRR)
问题:时间片轮转法无视了进程的固定优先级。如果把固定优先级加回系统,使其能够做到保证平均CPU获得的基础上,满足某些特别任务的高优先级需求?
问题:同一个线程可能承载不同的指令流;同一个指令流的行为在不同的执行阶段也可能发生改变。
多级反馈队列:在多级队列的基础上,实时动态检测每个线程的行为,并在原有队列不合适时为其更换到合适的队列。
内核线程
用户线程
- “内核线程(Kernel Thread)/用户线程(User Thread)”不要和“内核级线程(Kernel-Level Thread)/用户级线程(User-Level Thread)”搞混了。
- 前者是指线程运行时的CPU模式,而后者则是指操作系统是否知道它们的存在。
- 内核线程和用户线程都是内核级线程,而所谓的“用户级线程”则是指协程和纤程。
分配:应用程序的某个指令流发出一个从堆中申请内存的请求,堆的大小是已知的,某个应用程序内部的分配算法将从堆切出一部分内存并返回给这个请求。C语言的malloc、calloc等函数会从堆中申请内存。
使用:应用程序中的某个或某些指令流持有该内存块一段时间。在这段时间里,它们可能会读写该块内存。
释放:指令流不再使用这个内存块,并将其归还回堆中供以后申请。C语言的free函数将会释放内存,将内存归还给堆。
如果1MB分配不超过500次,那么不会产生任何内存碎片。但如果分配第501次,我们将发现1MB内存池的资源耗尽了,此时只有从100MB的内存池里面拿出一块来满足这个请求。这一次将产生99MB的内部碎片。而且,分配第505次后,我们将无法再满足更多请求。100MB分配就更惨了:只能做五次分配,此时系统中便无100MB的整块内存了,即使1MB内存池有足够总量也无法再分配了。
(所以都是各取所需哇
地址空间与进程:和指令流-线程的对应关系类似,操作系统并不直接知道某个应用程序的存在,它只能看到某些程序通过某些方法向某个地址空间加载数据并在那里执行。只要用户愿意,且应用程序的设计许可,用户可以在一个地址空间中装入多个应用程序,也可以将一个应用程序分成多个互相协作的地址空间。
进程(Process)的概念
- 在应用程序看来,自己的逻辑组织是一系列段。
- 在操作系统看来,应用程序的空间组织是一个或一系列进程。
进程的描述——描述符表
进程的描述——其它资源
一对一关系
一对多关系
段表的查询
分段不会产生内部碎片,但可能产生外部碎片。
局部性:一个活动操作的对象具备某种关联性。在这里是指,一个指令流(活动)在一段时间内访问的存储器总是有某些集中性(关联性的一种体现方式),那些集中性称为局部(短期调度的工作集)。它还可以细分为时间局部性和空间局部性。
- 时间局限性:指令流执行过程中,如果某存储单元被访问,那么在近期它很可能还会被再次访问。横切。
- 空间局限性:如果指令流访问某存储单元,那么近期内很可能会访问附近的其他存储单元。纵切。
快表(TLB)
分页的特点:
- 外部碎片:理论上讲,外部碎片在页式管理中不存在,因为物理内存不存在必须连续才能分配的要求。物理上不连续的页完全可以组成虚拟空间中的连续的段。
- 内部碎片:理论上讲,页式管理存在内部碎片,因为程序的每个段现在都按照页为最小粒度划分了。如果一个段不能被页整除,我们就必须要分配一整个页给它的残余部分。
页越大(一般定为4KB),产生的内部碎片就越多,但是TLB的利用效率就越高。反之,内部碎片少,但TLB利用率低。
基数树(Radix Trie)
进程的工作集
单层存储模型
缺页异常处理流程
问题:当工作集改变,需要包含新内容时,如何选择要被替换的老内容?页的换入换出需要读取外存,我们希望这种换出尽量少。
在某些资源分配策略下,增加资源总量反而导致性能下降和效率降低的现象。在这里是指,对于某些替换算法,允许的物理页数量越大,缺页率反而升高。
缺页异常:当页表中没有某个页时,产生操作系统可截获并处理的异常。
访问位A:当某个页被访问,其页表的访问位会被硬件置为。
脏位D(又脏位说明该页可写):当某个页被实际写入(内容遭修改),其页表的脏位会被硬件置位。
基本操作
其它操作