书《计算机操做系统》第四版(汤小丹编著)git
课程操做系统程序员
操做系统启动流程略了github
md和pdf下载:Chasssser算法
完整版包括收集的题目shell
如下仅为知识点数据库
操做系统是配置在计算机硬件上的第一层软件,是对硬件系统的首次扩充。其主要做用是管理好这些设备,提升他们的利用率和系统的吞吐量,并为用户和应用程序提供一个简单的接口,便于用户使用。(第一章第一段)编程
计算机系统中同时存在多个运行的程序,须要OS管理和调度。api
并行性:两个或者多个事件在同一时刻发生。数组
并发性:两个或者多个事件在同一时间间隔内发生。
“同时”访问:有的资源容许一段时间内由多个进程"同时"对它们进行访问,"同时"在微观上意义上,进程对该资源的访问是交替进行的。
互斥共享:有的资源虽然能够供给多个进程使用,可是一段时间内只容许一个进程访问该资源,故创建进程对这类资源的互斥访问。
利用多道程序设计技术,让每一个用户都以为有一个计算机专门为他服务
时分复用:利用某设备为一用户服务的空闲时间内,又转去为其余用户服务。经过利用处理机的空闲时间运行其它程序,提升处理的利用率
空分复用:利用存储器的空闲空间分区域存放和运行其余的多道程序,以此提升内存的利用率。
程序的执行不是一向到底,而是走走停停,向前推动的速度不可预知,这就是进程的异步性。
可是只要运行环境相同,OS须要保证程序运行的结果也要相同
进程控制:为做业建立进程、撤销(终止)已结束的进程、控制进程在运行过程当中的状态转换
进程同步:为多个进程(线程)的运行进行协调。
进程通讯:实现相互合做进程之间的信息交换。
内存分配
内存保护
地址映射
内存扩充
缓冲管理:缓和CPU和I/O设备速度不匹配的矛盾。
设备分配:设备控制表、控制器控制表
设备处理:设备驱动程序,实现CPU和设设备控制器之间的通讯。
文件存储空间的管理
目录管理
文件的读/写管理和保护
用户接口
程序接口
系统安全
网络的功能和服务
支持多媒体
■ 操做系统=装载器+通用子程序库
■ 问题:昂贵组件的低利用率
■ 顺序执行与批处理
■ 主要缺点:系统中的资源得不到充分利用,由于内存中只有一道程序
■ 保持多个工做在内存中而且在各工做间复用CPU
■ 多道程序交替执行,交替的条件是前一个正在执行的程序主动让出CPU的使用权。
■ 多道批处理系统主要考虑的是系统效率和系统的吞吐量(优势)。
■ 多道批处理系统缺点:平均周转时间长,无交互能力
■ 定时中断用于工做对CPU的复用
■ 交互性和及时性是分时系统的主要特征。
■ 实时系统的正确性,不只有计算的逻辑结果来决定,还取决于产生结果的时间。
■ 实时任务的类型:
周期性实时任务和非周期性实时任务,前者是指外部设备周期性地发出激励信号给计算机,使其周期性执行,以便周期性地控制某外部设备,后者无明显的周期性,可是都必须联系着一个截止时间。
硬实时和软实时,前者必须知足对截止时间的要求,后者对此没有严格要求
无结构
模块化
分层
自底向上的分层原则,肯定每一步的设计都是创建在可靠的基础上。
微内核结构
只将最基本的部分放入微内核中。
防止OS自己及相关数据遭到应用程序或无心的破坏,一般将处理机的执行状态分为:
系统态(内核态,内核态又称为管态):高权限,能访问全部的寄存器。
用户态:低权限,能访问指定的寄存器。
例子:
CPU执行操做系统代码的时候称为处理机处于管态。
函数调用并不会切换到内核态,而除零操做引起中断,中断和系统调用都会切换到内核态进行相应处理。
计算机的一些功能只有内核有权利访问,经过中断、异常和系统调用为应用程序提供方便。
在计算机运行中,内核是被信任的第三方
只有内核能够执行特权指令
方便应用程序
当外设链接计算机时,会出现什么现象?(中断)
当应用程序处理意想不到的行为时,会出现什么现象?(异常)
经过调用函数库,函数库又会调用对应的系统调用接口,从而获得系统服务。
系统调用时会有堆栈切换和特权级的转换,INT和IRET用于系统调用。
功能调用时没有堆栈切换,CALL和RET用于功能调用。
咱们要解决用户程序如何来解决系统的服务。就好象说咱们提供给银行对外提供服务,银行为了保证安全,它有不少的防御,这个防御又和对外提供服务这是有矛盾的。
为了方便用户来使用银行的服务,应该必须提供灵活的访问接口,又不能影响到银行的安全。
操做系统内核也是同样的,咱们须要来经过系统调用来提供一个接口,让应用程序既方便的使用内核提供的服务,又不至于用户的行为对我内核的安全产生影响
硬件处理
在CPU初始化时设置 中断使能 标志
注释:1)在许可外界打扰CPU的执行以前,CPU是不会对外界的任何中断请求发出响应的。
2)生成中断标志,一般是一个电平的上升沿或者说是一个高电平,CPU会记录这个事件。
我有一个中断标志,表示出现了一个中断,什么设备产生的,须要知道中断源的编号。
软件
现场保持 (编译器)
中断服务处理 (服务例程)
清除中断标记 (服务例程)
现场恢复 (编译器)
注: 都到了中断向量表,中断--中断服务例程,异常--异常服务例程,系统调用--总共占有一个中断编号,不一样系统调用功能由系统调用表来表示的。由系统调用表的不一样,选中不一样的系统调用实现。
若是是系统调用,因为系统调用的量很大,他在中断向量表里只占一个中断编号,不一样的系统调用的功能由系统调用表实现。
须要保存上下文信息。
我正在处理一个请求的时候,又来了一个请求这时候我怎么办,那咱们说在操做系统的里头呢?
它是硬件的中断,它是容许被打断的,也就是说我正在处理一个中断的时候,能够容许你再出现其余的中断。
若是两个中断源不一样,那这时候我能够经过优先级的高低,让一个日后推一段,或者说让一个暂停下来,那使得我能够同时在作交替在作处理。
中断服务例程里头,并非说我任何一个时刻均可以作任何一个处理,它会在必定的时间里禁止中断请求。
好比说我电源有问题,那可能其余的问题就变得不重要了,这时候我在作电源的处理的时候,我就会禁止掉其余中断。中断服务请求会一直保持到CPU作出响应。
好比说我在这里头虚拟存储里头,它访问到的存储单元的数据不存在,我正在从硬盘上倒数据进来。倒的过程中,它会用到磁盘I/O,这时候也会再有磁盘设备的中断,这时候是容许它能够作嵌套的。
系统调用是提供给应用程序使用的,由用户态发出,进入内核态执行。外部中断随时可能发生;应用程序执行时可能发生缺页;进程切换彻底由内核来控制。
进程是指一个具备必定独立功能的程序在一个数据集合上的一次动态执行过程。
进程包含了正在运行的一个程序的全部状态信息 :
内核选择一个就绪的进程,让它占用处理机并运行
如何选择?处理机调度算法
只有进程自己才知道什么时候须要等待某种事件的发生,即致使其进入等待状态的必定是进程自己内部缘由所致使的,不是外部缘由所致使的。
进程只能被别的进程或者操做系统给唤醒。
一个新进程被产生出来执行一个程序
当进程被建立完成并初始化后,一切就绪准备运行时,变为就绪状态
处于就绪状态的进程被进程调度程序选中后,就分配处处理机上运行
当进程表示它已经完成或者因出错,当前运行进程会由操做系统做结束处理(回收资源)
处于运行状态的进程在其运行期间,因为分配给它的处理时间片用完而让出处理机
当进程请求某资源且必须等待时
当进程要等待某事件到来时,它从阻塞状态变到就绪状态。
处在挂起状态的进程映像在磁盘上,目的是减小进程占用内存
进程在外存并等待某事件的出现(多加了一个关于进程的位置信息)
进程在外存,但只要进入内存,便可运行
(没法进入内存缘由:内存空间不够或者进程自己优先级不够高)
没有进程处于就绪状态或者就绪进程要求更多内存资源
当有高优先级等待(系统认为会很快就绪的)进程和低优先级就绪进程
对抢先式分时系统,当有高优先级等待挂起进程由于事件出现而进入就绪挂起(好比内存不够)
当有等待挂起进程由于相关事件出现
没有就绪进程或者挂起就绪进程优先级高于就绪进程
当一个进程释放足够内存,并有高优先级等待挂起进程
就绪队列、各类等待队列
进程状态变化时,它所在的PCB会从一个队列 换到另外一个
进程通讯是进程之间的信息交换,是进程进行通讯和同步的机制。
进程不借助任何共享存储区或数据结构,而是以格式化的消息(message)为单位,将数据封装在消息中,并利用操做系统提供一组通讯命令(原语)完成信息传递和数据交换。
发送进程利用OS所提供的通讯指令,直接把消息放到目标进程
(1)对称寻址方式;该方式要求发送和接受进程必须以显示方式提供对方的标识符。
系统提供命令:
send(receiver,message);//发送一个消息给接受进程receiver receive(sender,message);//接受进程sender发来的消息
(2)非对称寻址方式;在接受程序原语中,不须要命名发送进程。
系统提供命令:
send(P,message);//发送一个消息给接受进程P receive(id,message);//接受来自任何进程的消息,id变量能够设置为发送进程的id或者名字
(1)定长(消息长度)
(2)变长(消息长度)
(1)发送阻塞,接收阻塞
(2)发送不阻塞,接收阻塞
(3)发送不阻塞,接收不阻塞
创建方式:(1)显示创建连接命令;(2)发送命令自动创建链路
通讯方式(1)单向(2)双向
(增长了消息队列的队首指针,互斥和资源信号量)
发送原语首先根据发送区a中的消息长度a.size来申请一个缓冲区i,接着把a中的信息复制到缓冲区i中。得到接受进程内部标识符j,而后将i挂在j.mq上,因为该队列属于临界资源,因此执行insert先后都要执行wait和signal操做。
其中
mq//消息队列 mutex//对消息队列的互斥访问 sm//消息的资源信号量
调用接受原语receive(b),从本身的消息缓冲队列mq中摘下第一个消息缓冲区i,并将其中的数据复制到以b为首地址的指定消息接收区内。
发送和 接收进程,经过共享中间实体(邮箱 )完成通讯。该实体创建在随机存储器的公用缓冲区上,用来暂存信息。
信箱头:用于存放信箱的描述信息,如信箱标识符等
信箱体:由若干个能够存放信息的信箱格组成,信箱格数目和大小是在建立信箱时肯定的。
(1)邮箱的建立和撤销
(2)消息的发送和接收
Send(mailbox,message);//将一个消息发送到指定邮箱 Receive(mailbox,message);//从指定邮箱中接受一个消息
(1)私用邮箱:只有建立者才能接收消息
(2)公用邮箱:操做系统建立
(3)共享邮箱:建立进程指明接收进程
(1)一对一:专用通讯链路
(2)多对一:客户/服务器
(3)一对多:广播
(4)多对多:公共邮箱
其中
共享内存是把同一个物理内存区域同时映射到多个进程的内存地址空间的通讯机制
每一个进程都有私有内存地址空间
每一个进程的内存地址空间需明确设置共享内存段
同一进程中的线程老是共享相同的内存地址空间
快速、方便地共享数据;
最快的通讯方法;
一个进程写另一个进程当即可见;
没有系统调用干预;
没有数据复制;
不提供同步,必须用额外的同步机制来协调数据访问,好比由程序员提供同步
一个嵌套字就是一个通讯标识类型的数据结构,包含通讯目的的地址,端口号,传输层协议等
基于文件型:两个进程都运行在同一台机器上,嵌套字基于本地文件系统支持
基于网络型:非对称通讯方式,须要发送者提供接收者的命名
不只使用与同一台计算机内部的进程通讯,并且适用于网络环境中不一样计算机之间的进程通讯。
在OS中引入进程是为了让多个程序能并发执行,来提升资源利用率和系统吞吐量。
在OS中映入线程是为了减小程序在并发执行时所付出的时空开销,使得OS有更高的并发性。
线程是进程的一部分,描述指令流执行状态,它是进程中的指令执行流的最小单元,是CPU调度的基本单位。
调度的实质是一种资源分配,处理机调度是对处理机资源进行分配。
处理机调度决定系统运行时的性能:系统吞入量、资源利用率、做业周转时间、做业响应时间等….
高级调度(又称长程调度或者做业调度)-》做业级
低级调度(又称短程调度或者进程调度)-》进程(线程)级
中级调度(内存调度)-》内存
在进程/线程的生命周期中的何时进行调度?
好比3个进程,计算时间为12,3,3,到达顺序为P1,P2,P3(假设同一时刻到达)
则周转时间=(12+15+18)/3=15
若是到达顺序为P2,P3,P1
则测试周转时间=(3+6+18)/3=9
简单
平均等待时间波动比较大,好比短进程可能排在长进程后面
选择就绪队列中执行时间最短的进程占用CPU进入运行状态
就绪队列按照预期的执行时间长度来排序
新进程所须要的执行时间比当前正在执行的进程剩余的执行时间还要短,那么容许它抢先。
SPN算法中一组进程的平均周转时间
此时周转时间\(=(r_1+r_2+r_3+r_4+r_5+r_6)/6\)
修改进程执行顺序可能减小平均等待时间吗?
周转时间\(=(r_1+r_2+r_4-c_3+r_5-c_3+r_4+c_4+c_5+r_6)/6\)
$=(r_1+r_2+r_3+r_4+r_5+r_6+(c_4+c_5-2c_3))/6$
\(c_i\)表示进程\(P_i\)的执行时间(不必定等于周转时间)
选择就绪队列中响应比R值最高的进程
即按照R值来排序
R=(w+s)/s
w: 等待时间(waiting time) s: 执行时间(service time)
时间片结束时,按照FCFS算法切换到下一个就绪进程
每隔(n-1)个时间片进程,进程执行一个时间片q
进程在一个时间片内已执行完,马上调度,并将该进程从就绪队列中删除
进程在一个时间片内未执行完,马上调度,并将该进程放入就绪队列末尾
如:前台(交互)、后台(批处理)
如:前台–RR、后台–FCFS
设置多个就绪队列,为每一个队列赋予不一样的优先级,每一个队列采用FCFS算法,按队列优先级调度
对多个进程在执行顺序上进行调节,使并发执行的诸程序之间能按照必定的规则(时序)共享系统资源,并可以很好的相互合做,从而使程序的执行具备可再现性。
间接相互制约关系(互斥):因为共享系统资源致使
直接相互制约关系(同步):为完成同一任务而合做
好比打印机,磁带机,producer-consumer问题
enter section //进入区 critical section //临界区 exit section //退出区 remainder seciton//剩余区
空闲让进:无进程时,任何进程可进去
忙则等待:有进程在临界区时,其余进程均不能进入临界区
有限等待:有点等待时间,不能无限等待
让权等待(可选):不能进入临界区的进程,应释放CPU
软件实现方法,硬件实现方法。
local_irq_save(unsigned long flags); //关中断 critical section //临界区 local_irq_restore(unsigned long flags); //使能中断
知足线程\(T_i\)和\(T_j\)之间互斥的经典的基于软件的方法
int turn; //表示容许进入临界区的线程ID boolean flag[]; //表示进程请求进入临界区
flag[i]=true; turn=j; while(flag[j] && turn == j); //有一个条件不知足就进入临界区,不然一直等 /* *此时若是同时有两个进程进入临界区 *那么先写的那个进程能进入(后一个不知足),后的不能(都知足) */
flag[i]=false;
线程\(T_i\)的代码
do{ flag[i]=true; //线程i请求进入临界区 turn=j; while(flag[j] && turn == j); CRITICAL SECTION //临界区 flag[i]=false; REMAINDER SECTION //退出区 }while(true);
flag[0]=false; flag[1]=false; turn=0; do{ flag[i]=true; //线程i请求进入临界区 while(flag[j]==true){ if(turn!=i){ flag[i]=false; while(turn!=i){} flag=true; } } CRITICAL SECTION //临界区 turn=j; falsg[i]=false; REMAINDER SECTION //退出区 }while(true);
基于硬件提供了一些同步原语,好比中断禁用,原子操做指令等
操做系统提供更高级的编程抽象来简化进程同步,例如:锁、信号量,用硬件原语来构建
class Lock{ int value=0; } //忙等待锁 Lock::Acquire(){ while(test-and-set(value)) ;//spin } Lock::Release(){ value=0; }
复杂,须要两个进程间的共享数据项
须要忙等待,浪费CPU时间
信号量是操做系统提供的一种协调共享资源访问的方法
由一个整形变量sem(共享资源的数目)和两个原子操做组成
//P操做--申请使用资源 P()(Prolaag (荷兰语尝试减小)) -》wait sem--;//可用资源减小一 if sem<0,进入等待,不然继续 //可用资源用完了,须要等待其余线程释放资源 //V操做--释放可用资源 V()(Verhoog (荷兰语增长)) -》signal sem++; if sem<=0,唤醒一个等待进程
不能。由于自旋锁须要占用CPU,随时检查,有可能临界区的使用者退出时刚修改完,下一个进入者进入时资源才变成有效,就没法实现先进先出。
classSemaphore{ int sem; //共享资源数目 WaitQueue q; //等待队列 } Semaphore::P(){ sem--; if(sem<0){ //资源用完了 Add this thread t to q; block(p); //阻塞 } } Semaphore::V() { sem++; if (sem<=0) { //此时前面仍有等待线程 //从对应的等待队列里把相应的线程放入就绪队列 Remove a thread t from q; wakeup(t); } }
每一个临界区设置一个信号量,其初值为1
mutex = new Semaphore(1); //信号量初始化为1 //控制临界区的访问 mutex->P(); //信号量计数-- Critical Section; mutex->V(); //释放资源,信号量计数++
注意:
初始化若是是同步互斥,看资源数目,若是是条件同步,为0或者1
必须成对使用P()操做和V()操做
P()操做保证互斥访问临界资源
PV操做不能次序错误、重复或遗漏(但不要求P在V以前或者以后)
执行时不可中断
问题:
不申请直接释放,出现多个线程进入临界区的状况
只申请不释放,缓冲区没有线程,可是谁也进不去临界区
//此时的条件同步设置一个信号量,初始化为0 condition =new Semaphore(0); //实现一个条件等待,线程A要等到线程B执行完X模块后才能执行N模块 //线程A ---M--- condition->P(); ---N--- //线程B ---x--- condition->V(); ---Y--- //在B里释放信号量,使其0->1,若是B先执行完X模块,则A能够直接往下执行; //若是A先执行完就等待
有界缓冲区的生产者-消费者问题描述
问题分析
用信号量描述每一个约束
实现
Class BoundedBuffer { mutex = new Semaphore(1); fullBuffers = new Semaphore(0);//一开始缓冲区中没有数据 emptyBuffers = new Semaphore(n);//全都是空缓冲区 }
BoundedBuffer::Deposit(c) {//生产者 emptyBuffers->P(); //检查是否有空缓冲区 mutex->P(); //申请缓冲区 Add c to the buffer; mutex->V(); fullBuffers->V();//释放该资源,相等于缓冲区中多了一个数据 }
BoundedBuffer::Remove(c) {//消费者 fullBuffers->P();//检查缓冲区中是否有数据 mutex->P(); Remove c from buffer; mutex->V(); emptyBuffers->V();//释放空缓冲区资源 }
两次P操做的顺序有影响吗?
交换顺序会出现死锁,缘由在于自我检查空和满
管程是一种用于多线程互斥访问共享资源的程序结构
管程的使用
控制管程代码的互斥访问
管理共享数据的并发访问
若是是0个,就等同与一个临界区,若是是多个就是管程所特有的
Class Condition{ int numWaiting=0; //条件变量初值为0,若是在信号量里和资源数目一致 WaitQueue q; }
Condition::Wait(lock){ numWaiting++; //等待数目++ Add this thread t to q;//将本身放入等待队列当中 release(lock); //释放管程的互斥访问权限 shedule();//执行调度,切换线程need mutex require(lock);//请求访问权限 }
Condition::Signal(){ if(numWaiting>0){//等待队列不为空,即有另外的线程等待这个条件变量上,每一个变量对应一个队列 Remove a thread t from q;//将此线程从等待队列移动到就绪队列中 wakeup(t);//唤醒进程need mutex numWaiting--;//等待数目-- } }
classBoundedBuffer { … Lock lock;//一个入口等待队列 int count = 0; //写入缓冲区的数据的数目 Condition notFull, notEmpty;//两个条件变量 }
BoundedBuffer::Deposit(c) {//生产者 lock->Acquire(); //管程进入权申请 while (count == n) //n个缓冲区中都有数据了--对应**1 notFull.Wait(&lock);//就放弃管程使用权,等在notfull条件变量上 Add c to the buffer; count++; notEmpty.Signal(); lock->Release(); //管程进入权释放 }
BoundedBuffer::Remove(c) {//消费者 lock->Acquire(); //管程进入权申请 while (count == 0) //若是没数据 notEmpty.Wait(&lock);//就放弃管程使用权,等在非空条件上 Remove c from buffer; count--; notFull.Signal(); //读出一个数据后就释放notfull--对应**1 lock->Release(); //管程进入权释放 }
1.初始化
2.管程中写法
5个哲学家围绕一张圆桌而坐,桌子上放着5支叉子,每两个哲学家之间放一支
哲学家的动做包括思考和进餐,进餐时需同时拿到左右两边的叉子,思考时将两支叉子放回原处
如何保证哲学家们的动做有序进行?如:不出现有人永远拿不到叉子
#define N 5 // 哲学家个数 semaphore fork[5]; // 信号量初值为1 void philosopher(int i) // 哲学家编号:0 - 4 while(TRUE) { think( ); // 哲学家在思考 if (i%2 == 0) { P(fork[i]); // 去拿左边的叉子 P(fork[(i + 1) % N]); // 去拿右边的叉子 } else { P(fork[(i + 1) % N]); // 去拿右边的叉子 P(fork[i]); // 去拿左边的叉子 } eat( ); // 吃面条中…. V(fork[i]); // 放下左边的叉子 V(fork[(i + 1) % N]); // 放下右边的叉子 } //没有死锁,可有多人同时就餐
用信号量描述每一个约束
semphoare WriteMutex=1; int Rcount=0; semphoare CountMutex=1;
void Writer(){ P(WriteMutex); write; V(WriteMutex); }
void Reader(){ P(CountMutex); if (Rcount == 0) P(WriteMutex); ++Rcount; V(CountMutex); read; P(CountMutex); --Rcount; if (Rcount == 0) V(WriteMutex); V(CountMutex) } //此实现中,读者优先
读者优先策略
只要有读者正在读状态,后来的读者都能直接进入
如读者持续不断进入,则写者就处于饥饿
写者优先策略
只要有写者就绪,写者应尽快执行写操做
如写者持续不断就绪,则读者就处于饥饿
如何实现?
用信号量描述每一个约束
semaphore WriteMutex=1,ReadMutex=1,x=1; int Rcount=0,WRcount=0; semaphore CountMutex=1,WRMutex=1;
void Reader(){ P(x); P(ReadMutex); P(CountMutex); if(Rcount==0) P(WriteMutex); ++Rcount; V(CountMutex); V(ReadMutex); V(x); read; P(CountMutex); Rcount--; if(Rcount==0) V(WriteMutex); V(CountMutex); }
void Writer(){ P(WRMutex); if(WRcount==0) P(ReadMutex); WRcount++; V(WRMutex); P(WriteMutex); Write; V(WriteMutex); P(WRMutex); WRcount--; if(WRcount==0) V(ReadMutex); V(WRMutex); }
顶点
有向边
若是一组进程中每个进程都在等待仅由该组进程中的其它进程才能引起的事件,那该组进程是死锁的。
确保系统永远不会进去死锁状态
预防是采用某种策略,限制并发进程对资源的请求,使得系统在任什么时候刻都不知足死锁的必要条件(四个)
在使用前进行判断,只容许不会出现死锁的进程请求资源
在检测到运行系统进入死锁状态后,进行恢复
一般操做系统忽略死锁,大多数操做系统(包括UNIX)的作法
在死锁避免方法中,把系统的状态分为安全状态和不安全状态。
当系统处于安全状态时,能够避免发生死锁。反之,可能发生死锁。
系统处于安全状态,必定没有死锁
系统处于不安全状态,可能出现死锁,避免死锁就是确保系统不会进入不安全状态
\(n\) = 线程数量, \(m\) = 资源类型数量
\(Max\)(总需求量):$ n×m$矩阵
线程\(T_i\)最多请求类型\(R_j\)的资源$ Max[i,j] $个实例
\(Available\)(剩余空闲量):长度为\(m\)的向量
当前有 $Available[j] \(个类型为\)R_j$的资源实例可用
\(Allocation\)(已分配量):\(n×m\)矩阵
线程$T_i \(**当前分配**了\) Allocation[i, j] \(个\)R_j$的实例
\(Need\)(将来须要量):\(n×m\)矩阵
线程$T_i $将来须要 \(Need[i, j]\)个\(R_j\)资源实例
知足公式:
\(Need[i,j]= Max[i,j]–Allocation[i,j]\)
\(Request_i\) 线程\(T_i\)的资源请求向量
\(Request_i[j]\) 线程\(T_i\)请求资源\(R_j\)的实例
1.若是 \(Request_i ≤ Need[i]\), 转到步骤2。不然, 拒绝资源申请, 由于线程已经超过了其最大要求
2.若是\(Request_i≤ Available\), 转到步骤3。不然,\(T_i\)必须等待,由于资源不可用
3.经过安全状态判断来肯定是否分配资源给\(T_i\) :
生成一个须要判断状态是否安全的资源分配环境
\(Available= Available -Request_i\);//剩余-请求
\(Allocation[i]=Allocation[i]+Request_i\);//已分配+请求
\(Need[i]=Need[i]–Request_i\);//将来须要-请求
若是返回结果是安全,将资源分配给\(T_i\)
若是返回结果是不安全,系统会拒绝\(T_i\)的资源请求
1.Work 和Finish 分别是长度为m和n的向量初始化: Work = Available //当前资源剩余空闲量 Finish[i] = false for i:1,2, …, n. //线程i没结束 2.寻找线程Ti: (a) Finish[i] = false//接下来找出Need比Work小的线程i (b) Need[i]≤Work 若找到,执行3; 没有找到知足条件的Ti,转4。 3.Work = Work + Allocation[i]//线程i的资源需求量小于当前剩余空闲资源量, 因此配置给它的资源再回收 Finish[i] = true 转2 4.如全部线程Ti知足Finish[i] == true,//全部线程的Finish为True,代表系统处于安全状态 则系统处于安全状态
容许系统进入死锁状态
维护系统的资源分配图
按期调用死锁检测算法来搜索图中是否存在死锁
出现死锁时,用死锁恢复机制进行恢复
将内存中暂时不能运行的程序调到磁盘的对换区,同时将磁盘上能运行的程序调入内存
总体对换(进程对换),以进程为单位,须要系统支持功能对对换空间的管理,进程的换入和进程的换出
页面(分段)对换,以进程的一个页面或者分段为单位,有称部分对换,其目的是支持虚拟存储系统
文件区用于存放各种文件,对换区用于存放从进程换出的进程
实现从逻辑地址到物理地址的变换,借助页表来完成
从进程发出指定逻辑地址的访问请求,通过地址变换,到内存中找到对应的实际物理单元取出数据的总时间。
主要知足用户和程序员如下需求:
用户把本身的做业按照逻辑管理划分为若干段,每一个段都是从0开始编址,并有本身的名字和长度。所以,但愿要访问的逻辑地址是由段名(段号)和段内偏移量(段内地址)决定的。
在实现对程序和数据的共享时,是以信息的逻辑单位为基础的。分页系统中的页只是存放信息的物理单位(块),并没有完整的意义,段倒是信息的逻辑单位。为了实现段的共享,但愿存储管理能与用户程序分段的组织方式相适应。
有些段,会随着程序的使用不断增加。而事先又没法确切地知道数据段会增加到多大。
动态连接是指在做业运行前,并不把几个目标程序段连接起来。要运行时,先将主程序所对应的目标程序装入内存并启动运行,当运行过程当中有须要调用某段时,才将该段调入内存并进行连接。可见动态连接也要求以段做为管理的单位。
段号+段内地址
段号可算一个做业最长有多少个段,段内地址可算每一个段的最大长度
在分段存储管理方式中,做业的地址空间被划分为若干个段,每一个段定义了一组逻辑信息
在系统中为每一个进程创建一段映射表,简称“段表”。每一个段在表中占有一个表项。其中记录了该段在内存中的起始地址(基址)和段的长度。段表能够存放在一组寄存器中,以提升访问速度,但更常见的是将段表放在内存中。
在配置了段表后,执行中的进程可经过查找段表找到每一个段所对应的内存区。
段表是用于实现从逻辑段到物理内存区的映射。
为了实现进程逻辑地址到物理地址的变换功能,在系统中设置了段表寄存器,用于存放段表起始地址和段表长度TL。在进行地址变换时,系统将逻辑地址中的段号S与段表长度TL进行比较。若S>TL,表示段号太大。访问越界,因而产生越界中断信号;若未越界,则根据段表的起始地址和该段的段号+段内地址从而到的要访问的内存物理地址。
段表放在内存中时,每次访问一个数据都要两次方寸,解决方法和分页系统相似,设置一个联想寄存器,来保存最近经常使用的段表项。
a)、页是信息的物理单位,分页是为实现离散分配方式,其目的是消减内存的外零头,提升内存的利用率;分段中的段则是信息的逻辑单位,它含有一组其意义相对完整的信息,分段的目的是为了能更好地知足用户的须要。
b)、页的大小固定且由系统决定,由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,于是在系统中只能有一种大小的页面;而段的长度却不固定,决定于用户所编写的程序,一般由编译程序在对源程序进行编译时,根据信息的性质来划分。
c)、分页的做业地址空间是一维的,分页彻底是系统行为,即单一的线性地址空间,程序员只需利用一个记忆符,便可表示一个地址;而分段的做业地址空间则是二维的,分段是用户行为,程序员在标识一个地址时,既要给出段名,又要给出段内地址。
先将用户程序分段,在段内进行分页,为每个段赋予一个段名。在段页式系统中,其地址结构由段号、段内页号及页内地址三部分所组成。
配置一个段表寄存器,其中存放段表起始地址和段表长TL。比较段号与TL是否越界,从段表寄存器中获取段表始址找到段表,根据段表内的页表始址找到对应的页表,在根据页表的存储块找到内存中的物理块,从而获取物理地址。
段页式系统中,为了得到一条指令或数据,须三次访问内存:
① 访问内存中的段表,从中取得页表始址
② 访问内存中的页表,从中取出该页所在的物理块号,并与页内地址造成物理地址
③ 访问真正从第二次访问所得的地址中,取出指令或者数据
屡次访问内存,执行速度下降,所以在地址变换机构中增设一个高速缓冲寄存器。每次访问它时,都须同时利用段号和页号去检索高速缓存,若找到匹配的表项,即可以从中获得相应页的物理块号,用来与页内地址一块儿造成物理地址;若未找到匹配表项,则仍须要再三次访问内存。
在可变分区存储管理下,按地址排列的内存空闲区为:100KB、500KB、200KB、300KB和600KB。现有若干用户程序,其所需内存依次分别为212KB、417KB、112KB和426KB,分别用首次适应算法、最佳适应算法、最坏适应算法,将它们装入到内存的哪些空闲分区?哪一个算法能最有效利用内存?
可变分区存储管理中,做业的撤离一定会修改内存的“空闲区表”,试画出因做业撤离修改“空闲区表”的四种状况。
根据回收区的首地址,在空闲分区表(链)找到插入点,此时可能出现4种状况之一(假设空闲分区表按地址从低到高顺序排列):
解:
在采用页式存储管理的系统中,某做业的逻辑地址空间为4页(每页4096字节),且已知该做业的页表以下表。试求出逻辑地址14688所对应的物理地址。
程序在执行时出现的局部性规律,即在一较短期内,程序的执行仅仅局限于某个部分,相应地,它所访问的存储空间也局限与某个区域。
空间局限性:程序在一段时间内所访问地址可能集中在必定的范围内,其典型状况是程序的顺序执行
时间局限性:程序中的某条指令(数据)被执行(访问),不久后该指令可能再次被执行(访问)。产生的典型缘由是在程序中存在大量的循环操做。
虚拟存储器,是指具备请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。
程序被容许分红屡次装入内存
容许将暂不使用的代码和数据从内存中调至外存的对换区
能从逻辑上扩充内存容量,使得用户看到的内存容量远大于实际内存容量
在分页系统的基础上增长了请求调页功能和页面置换功能所造成的页式虚拟存储系统,容许用户程序只装入少数页面的程序和数据便可启动运行,经过上述功能将即将运行的页面调入内存,同时将暂不运行的页面换出到外存。
在纯分页的页表机制上增长其余字段造成的数据结构,用于将逻辑地址转换为物理地址
每当用户程序须要的页面再也不内存中,就产生缺页中断
选择的被淘汰页面是之后永远不使用的,或者是在最长(将来)时间内再也不被访问的
老是淘汰最早进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰
选择最近最久未使用的页面进行淘汰
LRU须要为每一个内存页面配置一个移位寄存器,来记录进程在内存中的各个页面使用状况
LRU还须要用一个特殊的栈来保存当前使用的各个页面的页面号
请求分段系统中,程序在运行以前,只须要调入少数几个分段(没必要调入全部的分段)就能够启动运行。当所访问的段不在内存中时,可请求OS将所缺的段调入内存。
在请求分段式管理中所须要的主要数据结构是请求段表
每当发现程序要访问的断再也不内存中,就有缺段中断机构产生一个中断信号,由OS将所需段调入内存。
在一条指令的执行期间产生和处理中断,可能发生屡次中断,但不可能出现一条指令被分割在两个段中。
被访问的段再也不内存时,须要地址变换。具体作法是先将所缺的段调入内存,并修改段表,而后利用段表进行地址变换。
记录了共享段的段号,段长,内存起始地址,状态(存在位),外村起始地址,共享进程计数(count)
当第一个使用共享段的进程提出请求时,由系统为该共享段分配一物理区,并调入该共享段,同时修改相应的段表(该段的内存地址)和共享段表,把 count 置为 1。当其它进程须要调用此段时,不需再调入,只需修改相应的段表和共享段表,再执行 count :=count+1 操做。
当共享共享段的某进程再也不使用该共享段时,修改相应的段表和共享段表,执行 count :=count-1 操做。当最后一共享此段的进程也再也不须要此段时,则系统回收此共享段的物理区,同时修改共享段表(删除该表项) 。
先利用段表寄存器中的段表长度与逻辑地址中的段号比较,若段号超界则产生越界中断。
再利用段表项中的段长与逻辑地址中的段内位移进行比较,若段内位移大于段长,也会产生越界中断。
注:在容许段动态增加的系统中,容许段内位移大于段长。
在段表中设置存取控制字段,用于规定对该段的访问方式。
环保护机构是一种功能较完善的保护机制。在该机制中规定:低编号的环具备高优先权。
OS 核心处于 0 环内;某些重要的实用程序和操做系统服务占居中间环;而通常的应用程序则被安排在外环上。
在环系统中,程序的访问和调用应遵循必定的规则:
同时在系统中运行的进程太多,由此分配给每个进程的物理块太少,不能知足进程正常运行的基本要求,使得每一个进程在运行时,频繁地出现缺页,必须请求系统调页,这样使得进程大部分时间用于页面置换,处理机效率急剧降低。
在一个请求分页存储管理系统中,进程P共有5页,页号为0至4。若对该进程页面的访问序列为3,2,1,0,3,2,4,3,2,1,0,4,试用最佳(Optimal)置换算法、LRU置换算法和FIFO置换算法,计算当分配给该进程的物理块数为3时,访问过程当中发生的缺页次数和缺页率。
独占设备,进程互斥地访问这类设备,即系统一旦将该类设备分配给某进程,便由该进程独占,直到用完释放。
共享设备,指一段时间内容许多个进程同时访问的设备
一种按照字节交叉工做的通道,不适用于链接高速设备,一般含有许多非分配型子通道,每一个子通道链接一个I/O设备,这些子通道按照时间片轮转方式共享主通道。
能够链接多台高速设备,但只含有一个分配型子通道,在一段时间内只能执行一道通道程序,控制一台设备进行数据传送,直到程序释放通道。利用率很低,可是传输效率很高。
数组多路通道结合了数组选择通道和字节多路通道,能使得各个子通道(设备)分时并行操做,含有多个非分配子通道。
用于实现CPU和设备控制器之间的通讯,该接口含有三类信号线:数据线,地址线和控制线
用于链接一个或者多个设备
用于实现对设备的控制
在多道程序中,利用一道程序模拟脱机输入时的外围控制机功能,再利用另外一道程序模拟脱机输出时外围控制机的功能,从而在主机的直接控制下,实现脱机输入输出。
在联机状况下实现的同时外围操做的技术,即为SPOOLing技术,假脱机技术。
指的是把磁头移动到指定磁道上花费的时间,该时间是启动磁头的时间\(s\)和磁头移动\(n\)条磁道所花费的时间之和,即为
\(T_s=m*n+s\)
其中m为一个常速,与磁盘驱动器的速度有关,通常磁盘,m为0.2;高速磁盘,m<=0.1
指的是指定扇区移动到磁头下所花费的时间
好比硬盘为15000 r/min,则每转须要4ms,从而平均旋转延时\(T_τ\)为2ms
指的是把数据从磁盘读出或者向磁盘写入数据所花费的时间,其大小和每次读写的字节数b和旋转速度有关:
\(T_t=\frac{b}{r*N}\)
其中r为磁盘每秒的转速,N为一条磁道上的字节数
当一次读写的字节数至关于半条磁道上的字节数时,\(T_t\)和\(T_τ\)相同,所以,可将访问时间\(T_a\)表示为:
\(T_a=T_s+\frac{1}{2r}+\frac{b}{rN}\)
根据进程请求访问磁盘的前后顺序进行调度
选择这样的进程,其要求访问的磁道与当前磁头所在磁道距离最近,使得每次的寻道时间最短,可是不能保证平均寻道时间最短
不只考虑将要访问的磁道和当前磁道间的距离,更优先考虑的是磁头当前的移动方向。
好比,当磁头向外移动时,SCAN算法考虑的下一个磁道应该是当前移动方向上距离最近的,直到最后再反向移动
规定磁头单向移动,当磁头移动到最外磁道并访问后,磁头当即返回到最里面的欲访问磁道,即将最小磁道号和最大磁道号构成循环进行扫描
例题:假设一个磁盘的每一个盘面上有200个磁道,现有多个进程要求对存储在该盘面上的数据进行访问,按照这些请求到达的前后次序,它们的访问位置分别处于5四、5七、3九、1八、90、16二、15四、3八、180号磁道上。假定当前磁头在100号磁道上。请给出按“先来服务(FCFS)”、“最短寻道时间优先(SSTF)”和“扫描(SCAN)”算法进行磁盘调度时各自实际的访问次序,并计算它们的平均寻道长度。(注:当采用扫描算法时,规定当前磁头正在向磁道号增长的方向上移动)
解:
FCFS算法访问次序:5四、5七、3九、1八、90、16二、15四、3八、180 平均寻道长度:55.3 SSTF算法访问次序:90、5七、5四、3九、3八、1八、15四、16二、180 平均寻道长度:27.1 SCAN算法访问次序:15四、16二、180、90、5七、5四、3九、3八、18 平均寻道长度:26.8
数据项是最低级的数据组织方式,可分为基本数据项和组合数据项
记录是一组关于数据项的集合,用于描述一个对象在某方面的属性
文件是指由建立者所定义的,具备文件名的一组相关元素的集合,可分为有结构文件和无结构文件两种,每一个文件都有文件属性。
文件属性
文件的逻辑结构,从用户观点出发看到的文件组织形式,即文件是由逻辑记录组成,是用户能够直接处理的数据及其结构,独立于文件的物理特性,又称为文件组织
文件的物理结构,又称为文件的存储结构,指系统将文件存储在外存上的存储组织形式
为了方便管理,含有三类信息
磁盘索引节点,每一个文件有惟一的磁盘索引节点,包含内容
内存索引节点,存放在内存中的节点,文件打开时,将磁盘索引节点拷贝到内次索引节点中,包含内容
外存的组织形式分为连续组织方式,连接组织方式,索引组织方式
为每一个文件分配一组相邻接的盘块
优势:
缺点:
为文件分配多个不连续的盘块,经过每一个盘块上的连接指针将同属于一个文件的离散盘块造成链表,由此造成连接文件。
优势:
缺点:
连接方式:
为每一个文件分配一个索引表(块),把分配给该文件的全部盘块号都记录在表(块)中,在创建一个文件时,只要在为之创建的目录项中填入指向改索引块的指针。
优势:
缺点:
为每一个文件分配一个索引表(块),把分配给该文件的全部盘块号都记录在表(块)中,在创建一个文件时,只要在为之创建的目录项中填入指向改索引块的指针。对于一个大文件,所分配的块已满,必须再分配一个索引块。
优势:
缺点: