现代操作系统读书笔记一到七章Word下载.docx
《现代操作系统读书笔记一到七章Word下载.docx》由会员分享,可在线阅读,更多相关《现代操作系统读书笔记一到七章Word下载.docx(55页珍藏版)》请在冰豆网上搜索。
1.用户程序与操作系统交互:
处理抽象
2.能进入内核的过程调用
用户态切换到核心态三种方法:
中断,异常,系统调用
3.TRAP指令:
副作用切换到内核态
1.7.3微内核
1.高可靠性,把操作系统划分成小的,定义良好的模块,只有微内核运行在内核,其他是普通用户程序
2.设备驱动:
崩溃不会导致系统死机
3.机制与策略分离
第二章:
进程与线程
2.1进程模型
1.多道程序设计:
CPU在多个程序之间快速切换
2.UNIX:
开始是相同,之后不同。
Windows:
一直不同。
3.进程退出的原因:
1.正常退出;
2.出错退出;
(异常处理)
3.严重错误;
(非法指令,引用错误内存,除零错误)
4.被杀死
4.进程层次
Windows:
没有层次的概念,所有进程地位相同
Linux:
进程及进程的子女们组成进程组
5.进程的三种状态:
1.运行态(实际占用CPU)
2.就绪态(可运行)
3.阻塞态(等待外部事件)
6.进程表:
储存进程状态(程序计数器,堆栈指针,内存分配状况,打开的文件状态。
账号等)
7.中断向量:
与每一个IO类关联
1.中断发生时,中断硬件程序将进程表中的重要数据压入堆栈,计算机跳到中断向量的地址
2.汇编语言设置新的堆栈(无法用C语言这类高级语言来描述)
8.多道程序设计
1.假设一个进程等待IO与停留在CPU的时间比为p,n个进程时,CPU使用率为
使用率=1–p^n
2.2线程(进程与线程)
1.定义:
传统操作系统中,每个进程有一个地址空间和一个控制线程
2.线程将应用程序分解成可以并行运行的多个顺序线程
3.使用多线程的原因:
1.并行实体共享同一个地址空间和所有可用数据的能力
2.线程更轻量级,所以他们比进程更快创建和撤销
3.同时需要大量IO和CPU计算时,多线程允许多个活动彼此重叠进行,从而加快执行速度
4.多核系统中,多线程可以真正实现并行
5.例子:
多线程/单线程web服务器
1.第三种设计(有限状态机:
并行,非阻塞系统调用,【中断】):
唯一的线程对请求进行考察,如果需要IO,则启动一个非阻塞IO,服务器在表格里记录当前请求,然后处理下一个事项。
6.线程模型
1.进程:
集中程序运行的相关资源(地址空间,全局变量等)
2.线程:
程序计数器,寄存器,堆栈,共享的地址空间,多个线程的执行能力。
7.线程之间没有保护:
1.不可能
2.不需要(线程之间是合作关系)
8.每个线程都有自己的堆栈
9.thread_yield:
不同于进程,线程无法使用时钟中断强制线程让出CPU
10.线程引入的问题
1.fork系统调用是否应该复制子线程
2.共享文件冲突
4线程实现
1.用户空间实现
1.每个进程需要有其专门的线程表,由运行时系统管理
2.优点
1.可以在不支持线程的操作系统上实现多线程
2.线程切换速度快(调用运行时系统的过程,不需要刷新和上下文切换)
3.允许每个进程有自己定制的调度算法
4.有较好的拓展性(内核线程需要固定的表格空间和堆栈空间)
3.缺点
1.某个线程进行阻塞调用会引起所有其他线程阻塞
1.使用非阻塞系统调用
2.阻塞提前通知(select系统调用)
2.页面故障阻塞其他线程
3.除非线程放弃CPU,否则其他线程(包括调度线程)无法运行(没有时钟中断)
1.运行时系统也给与时钟中断:
不好,不可能而且开销大
2.内核线程
1.内核有记录所有线程的线程表
2.使用环保方法回收线程
3.在线程级别使用调度算法:
如果线程的操作比较多,会带来很大的开销
4.信号:
是发给进程的。
当多个线程注册时,会出问题
3.混合实现
1.使用内核级线程,将用户级线程与某些或全部内核线程多路复用(很灵活)
4.调度机制
1.内核给每个进程安排一定数量的虚拟处理器并且让运行时系统分到线程上
2.进程被阻塞后,内核通知运行时系统(upcall)
3.根据中断决定是否继续
5.弹出式线程
1.一个消息的到达导致系统创造新的线程处理消息-》弹出式线程
2.优点:
没有历史,创建迅速
6.重写单线程代码
1.私有的全局变量
2.可重入的库
1.重写整个库
2.为每个过程提供wrapper,标志该库正在被使用中
3.信号:
内核不知道用户级线程,因此不容易将信号发给正确的线程
4.堆栈管理:
内核不了解线程,无法自动增长,可能会造成线程堆栈出错。
2.3进程间通信
1.三个基础问题
1.进程如何把信息传递给另一个·
2.确保两个或多个进程在关键活动中不会交叉
3.进程执行的正确顺序
2.竞争条件:
两个或多个进程读写共享数据,最后结果取决于进程执行的精确时序。
3.临界区:
多个进程中访问共享区域的程序段
1.互斥:
不能同时多个进程使用共享变量或者文件
2.临界区解决方案四个条件
1.任何两个进程不能同时处于临界区
2.不应对CPU的数量和速度有任何的假设
3.临界区外的程序不应阻塞其他程序
4.不能使程序无限期等待进入临界区
3.解决方案(基于忙等待:
进程如不能进入互斥区,则会一直原地等待)
缺点:
1.可能导致优先级反转问题
2.浪费CPU
3.用户级线程会一直忙等待,从而没用办法让拥有锁的线程运行
1.屏蔽中断:
进程进入临界区之后屏蔽所有中断(CPU不会切换)
评价:
不好的方案
1.不能把屏蔽中断的权力交给用户进程(不打开中断则系统会终止)
2.多处理器时不能解决互斥
2.锁变量:
共享锁,程序在进入临界区之前检查锁的值
评价:
无法解决临界区问题
3.严格轮换法
1.可以解决,但为忙等待。
只有有理由认为等待时间很短的情况下才使用忙等待(锁被称为自旋锁)
2.在一个进程比另一个进程慢很多的情况下,不好(违反条件三)
4.Peterson解法
可以解决,满足四大条件
5.TSL指令(硬件解法)
TSLRXLOCK:
测试并加锁,把LOCK值读到RX并在LOCK上存入1。
原子操作
可以阻止所有处理器访问LOCK(屏蔽中断只能屏蔽本地处理器)
4.睡眠——唤醒方案(进程无法进入临界区时会阻塞)
‘1.原语:
生产者——消费者问题:
一个发给未睡眠进程的信号丢失了
2.解决方案
1.唤醒等待位:
唤醒时生产者置1,消费者睡眠前检查该位,若为1,则清除该位并继续保持清醒(不好,多进程时需多个等待位)
2.信号量(semaphore):
检查数值,修改变量等应为原子操作
1.在进入一个关键代码段之前,线程必须获取一个信号量;
一旦该关键代码段完成了,那么该线程必须释放信号量。
其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。
2.实现方法:
操作系统在执行以上事务时屏蔽中断
3.另一种用途:
互斥锁
3.互斥锁:
只需要一个二进制位
与忙等待差异:
在未获得锁时,调用另外的线程
4.如何共享锁?
a)共享数据结构可以存放在内核并且只能用系统调用访问
b)让进程与其他的进程共享部分地址空间
5.条件变量
1.允许线程因为某些未达到的原因而阻塞
2.允许被阻塞而等待的线程原子性进行
3.经常与互斥量一起使用:
让一个线程锁住一个互斥量,当他不能获得期待结果时等待一个条件变量。
有另外一个线程发信号唤醒。
4.条件变量不会存在于内存(发出后丢失)
5.管程:
一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据
1.任何一个时刻管程里只能有一个活动的进程
2.第二个进程将被挂起直到活跃进程离开
3.如果一个条件变量上有若干程序在等待,则执行signal操作以后,系统只能从中任选一个恢复
4.实现:
JAVAsynchronized关键字
5.劣势
1.操作系统是C写的,没有管程的概念
2.分布式系统无法避免
6.消息传递
1.使用系统调用send和receive
2.潜在问题:
消息丢失,消息认证,消息传递速率低
3.编址方法
1.为每个进程分配一个唯一的地址
2.引入新的数据结构:
信箱。
消息发往信箱。
(解决消费者生产者问题)
7.屏障:
在每个阶段结尾安放屏障,当一个进程达到屏障时,它被屏障阻拦,直到所有进程都达到屏障
2.4调度
1.定义:
多个进程就绪是,CPU选择下一个将要执行的进程的方法。
2.进程行为:
IO密集型(web服务器)和CPU密集型(象棋软件)。
越来越多的软件倾向于IO密集型,应该多运行这类进程以保持CPU使用率
3.何时调度:
1.创建新进程时,应该先调度父进程还是子进程
2.进程退出时
3.进程阻塞时(IO,信号量等)
4.IO中断发生时
4.调度算法定义:
1.抢占式:
挑选一个进程,并且让进程运行某个固定时段的最大值,之后挂起
2.非抢占式:
挑选一个进程,让进程运行直到其阻塞或者自动释放CPU
5.调度算法目标(所有系统):
1.公平:
每个进程公平的CPU份额
2.策略强制执行:
所宣布的策略执行
3.平衡:
系统所有部分都忙碌
6.调度算法分类:
1.批处理:
处理周期性作业,广泛的商业应用
1.调度算法目标:
1.吞吐量throughout:
系统每小时完成的作业数量
2.周转时间turnaroundtime:
从一个批处理作业提交时刻开始直到作业完成时刻位置的平均时间
3.CPU利用率
2.具体调度算法:
1.先来先服务(first-come)
优点:
易于理解,便于实现
缺点:
同时运行IO密集型和CPU密集型程序时效率低下
2.最短作业优先(不可抢占)
1.计算公式:
2.只有所有作业都可同时运行且运行时间可以预知的情况下才能使用
3.最短剩余时间优先:
最短作业优先的抢占版
1.新作业到达时,整个时间与当前进程的时间做比较,运行剩余时间较少的作业
2.交互式系统
1.响应时间:
发出指令到相应的时间
2.均衡性:
满足用户的期望
2.具体调度算法
1.轮转调度:
最古老,最简单,最公平,使用最广
1.每个进程被分配时间片,时间片结束时切换进程
2.时间片
1.过长:
对短命令的交互请求时间变长
2.过短:
过多进程切换,降低CPU效率
2.优先级调度:
每个进程赋予优先级,优先级高的进程先执行
1.使IO进程良好运行的算法:
进程优先级为1/f,其中f是进程在上一时间片中实际运行的比例(IO进程会得到较高优先级)
2.多优先级队列:
低优先级可能出现饥饿现象
3.多级队列
1.实现方法:
最高优先级的进程获得1个时间片,之后优先级下降并在下次运行时获得两倍的时间片
4.最短进程优先
1.根据过去进程运行时间预测并执行估计运行时间
2.老化算法:
当前测量值和先前估计值进行加权平均(1/2比较好,右移一位即可)
5.保证调度:
每个进程获得1/n的时间
6.彩票调度:
向进程提供各种系统资源的彩票,某些进程可以协作获得更多彩票。
不错的方法
7.公平分享调度:
每个用户获得等量的CPU时间
3.实时系统
1.满足截止时间:
避免丢失数据
2.可预测性:
在多媒体系统中避免品质降低
2.分类
硬实时:
必须满足绝对的截止时间
软实时:
虽然不希望偶尔错失,但是可以容忍
2.周期性时间公式
M个周期时间,事件i以周期Pi发生,需要用Ci的CPU时间,那么这个系统可调度的条件是
7.调度机制与策略:
将调度机制与调度策略分离
例子:
系统使用优先级调度,但是把赋予优先级的行为委托给进程。
8.线程调度
1.用户级线程:
内核不知道线程,用户进程调用专门定制的线程调度程序
2.内核级线程:
时间片。
2.5经典IPC(Inter-ProcessCommunication)问题
1.哲学家进餐
1.随机事件解法:
可能因为不可靠的随机数字而失败
2.读者-写者问题:
不能让写者无法写入数据
第三章存储管理
3.1无存储器抽象:
程序直接访问物理内存
1.不能在内存里【同时】运行多个程序
2.实现并行可采用多线程编程:
不现实
3.运行多道程序的方法
1.交换:
保证一个时刻只有一个程序在内存里
2.特殊硬件:
防止进程相互干扰
不能直接使用绝对物理地址,装载器需要一定方法分别地址和常数
4.一些问题
1.用户系统如果可以寻址内存的每个字节,就有可能破坏操作系统
2.多道程序运行非常困难
3.2地址空间抽象
1.概念:
一个进程可用于寻址内存的一套地址集合,一般独立与其他进程的地址空间,除某些情况下需要共享
2.解决方法
1.动态重定位:
基址寄存器和界限寄存器
缺点:
,每次访问都需要加法和比较运算
2.交换技术:
将一个进程完整调入内存,使其运行一段时间后再存回硬盘
1.换入后使用硬件重定位
2.产生空洞,需要内存紧缩
3.现代程序需要内存较多,但是硬盘速度慢,交换时间长
4.注意:
进程大小如果增长,需要辅助手段。
解决方案:
移入时分配额外内存,再次交换出去时不交换额外的。
3.空闲内存管理
1.位图存储:
每个字需要1位位图
优点:
空间少
缺点:
分配内存时需要在位图里寻找指定长度的0串,费时。
2.链表管理:
维护一个记录已分配内存段和空闲内存段的链表,每个链表的节点或包含一个进程,或者两进程之间的空闲区
优点:
进程终止或者被换出是链表的更新非常直接
具体分配方法:
1.首次适配firstfit:
沿列表搜索直到找到一个足够大的空间
2.下次适配nextfit:
首次适配之后,从上次结束的地方开始搜索。
(性能略低于首次适配)
3.最佳适配bestfit:
搜索整个链表,找出能容纳进程的最小空闲区。
(速度较慢,会产生大量无用的小空闲区)
4.最差适配worstfit:
分配最大的空闲区(也不好)
5.为进程和空闲区保存单独链表
a)优点:
提高分配算法速度
b)缺点:
增加内存复杂度和内存释放速度变慢
6.快速适配quickfit:
为常用大小的空闲去维护单独的链表
3.3虚拟内存
1.基本思想:
每个程序拥有自己的地址空间,这个空间被分割成许多块,每一块称作一页page,page被映射到物理内存,但是只有某些页真正在内存中。
操作系统调用不存在页面的时候,引发缺页中断
2.分页技术
1.有程序产生的地址被称为虚拟地址,它们被称为虚拟地址空间。
地址空间里的单元成为页面,在物理内存对应的单元称为页框pageframe。
2.是用虚拟内存时,地址不是送到内存总线,而被送到内存管理单元(memorymanagementunit,MMU)MMU将虚拟地址映射成物理地址。
内存对MMU一无所知
例子:
16位虚拟地址对应15位物理地址,输入的虚拟地址被分为4位页面和12位偏移量,在页表中查询,之后组成15位实际地址
3.页表
一个把虚拟页面映射成页框的函数
2.页表项的结构
1.页框号
2.在/不在位
3.保护位
4.访问位和修改位
5.禁止高速缓存位:
对映射到设备寄存器的页面非常重要
3.不在内存的页面的硬盘地址不是页表的一部分:
缺页中断时,该页面的磁盘地址等信息保存在操作系统的内部软件上
4.加速分页
1.主要问题
1.虚拟地址到物理地址的映射必须非常快
2.如果虚拟地址很大,页表也会很大
2.极端解决方案
1.页表全部在寄存器里
优点:
简单,映射过程中不需要访问内存
缺点:
页表很大时代价高昂,每一次上下文切换都必须装载整个页表,性能低
2.页表全在内存里
上下文切换快
每条指令执行都需要访问内存
3.现实解决方法
1.转换检测缓冲区translationlookasidebuffer,TLB
1.本质:
把虚拟地址直接映射成物理地址的小型硬件
2.使用:
传入的虚拟页号并行匹配
3.未命中:
MMU未检查到有效匹配项,则进行页表查询,从TLB淘汰一个表项,并用新页表项代替
4.软失效:
页面不在TLB但是在内存:
更新TLB,几纳秒
硬失效:
页面不在内存:
缺页中断,磁盘IO,几毫秒
4.大内存页表
1.多级页表:
32位虚拟地址划分成页表1,页表2,偏移量三部分
原因:
避免全部页表一直在内存(一般程序只有少量的正文段,数据段和堆栈段,中间是大量空洞,访问空洞时强制缺页中断并发信号)
2.倒排页表(invertedpagetable,64位机器):
每一个页框对应一个页面
节省空间
从虚拟地址到物理地址的转换困难(必须搜索整个表项来寻找(进程,虚拟页面)对)
建立一张散列表,用虚拟地址来散列,相同hash值的表链在一起
3.4页面置换算法:
缺页中断时,操作系统必须淘汰一个旧页面/web服务器淘汰一个高速缓存项
1.最优页面置换算法:
用X条指令后才会用到来标记页面,置换X最大的页面
已知最好算法
不可能实现
2.最近未使用页面置换算法(notresentlyused,NRU):
启动进程时,系统把页面的访问位(R)和修改位(M)置零,R位被定期清零,以区别最近是否访问过。
页面分为4类:
1.没有被访问和修改
2.没有被访问,已修改
3.被访问,没有修改
4.访问修改
NRU算法在类标号最小的非空集里挑选一个页面淘汰
简单易实现
缺点:
性能不是最好的
3.先进先出页面置换算法(FIFO):
淘汰最老页面,可能会淘汰很有用的,不单纯使用
4.第二次机会页面置换算法(secondchance):
检查最老页面的R位,如果是0,置换之,否则清零并把该页面放到链表尾端。
本质:
找寻一个最近的时钟间隔以来没有被访问过的页面
5.时钟页面置换算法(clock):
第二次机会页面的时钟版
6.最近最少使用页面置换算法(LRU,LeastRecentlyUsed)
实现方法:
需要在内存里维护所有页面的链表,最近最多的使用的页面在表头,最近最少的页面在表尾
每次访问内存都必须更新整个链表,费时
特殊硬件实现方法:
1.64位计数器C,每个页表都有一个计数器,每次执行完以后加1,缺页中断时置换计数器最小的页面
2.N*N矩阵。
初值为0,访问页框k时,硬件首先把k行的位都设置成,再把k列的位都设置成0。
任何时刻二进制数值最小的行对应页面会被置换
7.软件模拟的LRU
1.最不常用算法(NFU):
每个页面与软件计数器相连,每次时钟中断是操作系统扫描所有页面并将R位加到计数器上,置换计数器值最小的页面
记忆太久,操作系统可能会置换有用的页面
2.老化算法aging:
在R位加入之前,计数器右移一位(相当于过去访问次数*1/2),然后把R加到计数器最左边。
置换计数器值最小的页面。
不能确定时钟滴答中哪个页面被先访问
计数器只有有限位数,限制了其对以往页面的记录(实际中一般够用)
8.工作集页面置换算法
1.定义:
一个进程当前正在使用的页面的集合称为工作集
2.分页系统会设法跟踪工作集,在进程运行之前就预先调页
3.大多数进程不会均匀访问地址空间,而是一小部分页面
4.缺页中断时,淘汰不在工作集的页面。
5.近似:
过去的t秒实际运行时间中进程所访问的页面的集合
6.算法:
9.工作集时钟页面置换算法:
工作集算法的时钟版本
10.小结:
最好的算法是老化算法和工作集时钟算法
3.5分页系统的设计问题
1.局部分配策略与全局分配策略
1.局部算法可以有效地为每个进程分配固定的内存片段
工作集,FIFO,LRU
2.全局算法