1.1作为用户与计算机硬件之间的接口
向上层提供的服务
-
GUI图形化用户接口
-
命令接口
-
程序接口
1.2操作系统的特征
-
并发
-
多个事件在同一事件间隔内发生
-
宏观上同时发生,微观上交替发生
-
-
共享
-
系统中的资源可供内存中的多个并发执行的进程共同使用
-
-
虚拟
-
把一个物理上的实体变为若干个逻辑上的对应物
-
时分复用技术与空分复用技术
-
-
异步
-
在多道程序环境下,允许多个程序并发进行,进程的执行是走走停停,以不可预知的速度向前推进
-
1.3操作系统的运行机制
-
内核程序与应用程序
-
普通程序员写的也是应用程序
-
-
特权指令与非特权指令
-
只有内核才能使用特权指令
-
CPU在设计时就划分了特权指令与非特权指令
-
-
CPU的内核态与用户态
-
处于内核态时可以运行特权指令
-
PSW程序状态字寄存器 1表示内核态,0表示用户态
-
用户态到内核态,由中断引起,硬件自动完成
-
1.4中断与异常
-
中断是让操作系统内核夺回CPU使用权的唯一途径
-
内中断与外中断
-
内中断(异常):用户态执行陷入指令主动让出CPU控制权给操作系统内核
-
外中断(中断):与当前执行的指令无关,信号来源于CPU外部(例如时钟和IO设备)
-
1.5系统调用
-
应用程序可以通过系统调用来请求获得操作系统内核的服务
1.6操作系统体系结构
-
内核功能与非内核功能(如GUI)
-
-
大内核
-
将操作系统的主要功能模块都作为系统内核,运行在核心态
-
高性能
-
内核代码庞大,结构混乱,难以维护
-
-
微内核
-
内核功能少,结构清晰,方便维护
-
需要频繁地切换CPU状态,性能低下
-
-
分层结构
-
每层可调用更低一层
-
-
模块化
-
将内核划分为多个模块,各模块之间可相互协作
-
-
外核
1.7操作系统引导
-
BIOS基本输入输出系统
-
基本步骤
-
CPU从一个特定的主存地址开始,取指令,执行ROM中的引导程序(先进行硬件自检,再开机)
-
将磁盘的第一块——主引导记录读入内存,执行磁盘引导程序,扫描分区表
-
从活动分区(安装了操作系统的分区)读入分区引导记录,执行其中的程序
-
从根目录下找到完整的操作系统初始化程序(启动管理器)并执行,完成开机
-
2.1进程
-
程序是静态的,进程是动态的
-
操作系统用不重复的UID(uesr)、PID(process ID)来区分不同的进程
-
UID、PID等都被保存在一个数据结构PCB(process control block)中,即进程控制块
-
PCB是进程存在的唯一标志,当进程被创建时,操作系统为其创建PCB,进程结束时会回收PCB
-
-
一个进程实体(进程映像)由PCB、程序段、数据段组成
-
进程是动态的,进程实体是静态的
-
进程是进程实体的运行过程,是系统进行分配和调度资源的一个独立单位
-
2.2进程的状态
-
创建
-
就绪 已经具备运行条件,但是由于没有空闲CPU,而暂时不能运行
-
运行 时间片到,或处理机被抢占,进程由运行态变为就绪态
-
阻塞 在进程运行的过程中,可能会请求等待某个事件的发生,此时操作系统会让该进程进入阻塞态,然后让另一个处于就绪态的进程在CPU上运行
-
终止
进程的组织
-
链接方式
-
索引方式
2.3进程控制
-
用原语实现,原语具有原子性,即一气呵成,状态的转换不能被中断
-
利用 开中断指令 关中断指令 这两特权指令来实现原子性
-
进程的创建
-
申请空白PCB
-
为新进程分配所需资源
-
初始化PCB
-
将PCB插入就绪队列
-
-
创建进程的事件
-
用户登录
-
作业调度
-
提供服务
-
应用请求
-
-
进程的终止
-
从PCB集合中找到需要终止的PCB
-
若程序正在运行,立即剥夺CPU,将CPU分配给其他进程
-
终止其所有子进程
-
将该进程拥有的所有资源归还给父进程或操作系统
-
删除PCB
-
-
终止进程的事件
-
正常结束
-
异常结束
-
外界干预
-
-
进程的阻塞
-
找到要阻塞的进程的PCB
-
保护进程运行现场,将PCB状态设置为阻塞态,暂时停止进程运行
-
将PCB插入相应事件的等待队列
-
-
引起阻塞的事件
-
需要等待系统分配某种资源
-
需要等待相互合作的其他进程完成工作
-
-
进程的唤醒
-
在事件等待系统分配某种资源
-
将PCB从等待队列移除,设置进程为就绪态
-
将PCB插入就绪队列,等待被调度
-
-
进程的切换(就绪到运行,运行到就绪)
-
将运行环境信息存入PCB
-
PCB移入相应队列
-
选择另一个进程执行,并更新其PCB
-
根据PCB恢复进程所需要的运行环境
-
-
引起切换的事件
-
当前进程事件片到
-
有更高优先级的进程到达
-
当前进程主动阻塞
-
当前进程终止
-
2.4进程通信
-
共享存储
-
为避免出错,要保证各个进程对共享空间的访问是互斥的
-
基于数据结构的共享存储,更低级
-
基于存储区的共享存储,更高级
-
-
消息传递
-
进程间的数据交换以格式化的消息为单位,包括消息头,消息体
-
直接通信方式,类似IP数据报,直接指明接收方ID
-
间接通信方式,通过信箱间接通信
-
-
管道通信
-
管道是一个特殊的共享文件,pipe文件,即在内存中开辟一个大小固定的内存缓冲区,类似循环队列
-
信息的流向的单向的,如果要实现双向同时通信,则需要设置两个管道
-
当管道满时,写进程堵塞,管道空时,读进程堵塞
-
管道中数据被读出则消失,为防止错乱有两种解决办法
-
一个管道运行多个写进程,只运行一个读进程
-
允许多个写进程,读进程,但会让各个进程轮流从管道中读数据(Linux方案)
-
-
2.5线程的概念
-
引入线程后,线程成为了程序执行流的最小单位
-
线程是一个基本的CPU执行单元,也是程序执行流的最小单位
-
进程内的各线程也可以并发,提高了系统的并发度
-
进程只作为除CPU之外的系统资源的分配单元(打印机等)
-
进程内的线程之间的切换,不需要切换进程环境,系统开销更小
-
-
线程的实现
-
用户级线程
-
线程库在用户态运行,不需要操作系统的干涉
-
不需要切换到核心态,线程管理的系统开销小,效率高
-
当一个线程被阻塞,其他线程都会被阻塞,并发度不高
-
-
内核级线程
-
线程的管理工作由操作系统内核完成
-
内核级线程的切换必须要在核心态下才能完成
-
一个用户进程会占用多个线程,线程切换由操作系统内核完成,需要切换到核心态,线程管理成本高,开销大
-
-
多线程模型
-
一对一模型
-
多对一模型
-
多对多模型
-
-
-
线程的组织与控制
-
TCB(线程控制块)
-
-
2.6调度
-
当有大量任务要处理时,由于资源有限,需要确定某种规则来决定处理这些任务的顺序,这就是调度研究的问题
-
三个层次
-
高级调度(作业调度)
-
按一定规则从外存的作业后备队列中挑选一个作业调入内存,创建进程,每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时撤销
-
-
低级调度(进程调度/处理机调度)
-
从就绪队列选取一个进程,将处理机分配给他
-
最基本调度,频率很高,几十毫秒一次
-
-
中级调度(内存调度)
-
内存不够时,将某些进程的数据调出外存,等待重新调入
-
暂时调到外存的等待状态叫做挂起状态,被挂起的进程PCB会被组织成挂起队列
-
一个进程可能被多次调入调出内存,因此频率比高级调度高
-
-
挂起
-
就绪挂起
-
阻塞挂起
-
-
-
-
调度器/调度程序(scheduler)
-
决定让谁运行,运行多长时间
-
何时触发调度程序?
-
创建新进程
-
进程退出
-
进程阻塞
-
IO中断发生
-
-
调度的对象根据操作系统的不同可以是进程或者线程
-
-
闲逛进程,没有其他就绪进程的时候,运行闲逛进程
-
优先级最低
-
可以是0指令占一个完整的指令周期(指令周期末尾例行检查中断)
-
能耗低
-
2.7调度算法
-
先来先服务(FCFS)
-
对长作业有利,对短作业不利,不会导致饥饿
-
-
短作业优先(SJF)
-
短作业优先算法,非抢占式,选择已到达且运行时间最短的作业
-
最短剩余时间优先算法,抢占式,每当有新进程加入就绪队列改变时就需要调度,如果新达到的进程剩余时间比当前运行的进程剩余时间更短,则抢占,当一个进程完成时也如此做。抢占式更快
-
缺点:对短作业有利,对长作业不利,可能产生饥饿现象,如果有短作业不断到来,可能让长作业长时间得不得服务,可能被饿死
-
-
高响应比优先(HRRN)
-
选择高响应比的进程 响应比=等待时间+要求服务时间/要求服务时间
-
非抢占式,即只有当前进程主动放弃CPU时才进行调度
-
较为综合
-
-
时间线轮转调度算法(RR)
-
常用于分时操作系统,更注重响应时间
-
就绪队列
-
当时间片到或者进程结束则从就绪队列选取一个进程,所以为抢占式
-
若时间片到,进程被抢占,则该进程进入队尾
-
-
优先级调度算法
-
抢占式或者非抢占式
-
优先数越大,优先级越高
-
系统进程高于用户进程,前台进程高于后台进程
-
操作系统更偏好IO型进程
-
若源源不断有优先级高的进程准备就绪,可能导致饥饿
-
-
多级反馈队列调度算法
-
抢占式
-
设置多级就绪队列,各队列优先级从高到低,时间片从小到大
-
-
-
多级队列调度算法
-
2.8进程同步与互斥
-
进程互斥的软件实现
-
单标志法
-
每个进程进入临界区的权限智能被另一个进程赋予
-
-
双标志先检查法
-
使用布尔数组实现
-
违反了忙则等待原则
-
-
双标志后检查法
-
先上锁后检查
-
解决了忙则等待,违背了空闲让进,有限等待原则,会产生饥饿现象
-
-
peterson算法
-
结合单双标志法,如果双方都想进入临界区,尝试谦让
-
turn的值设置为对方的编号
-
-
-
进程互斥的硬件实现
-
中断屏蔽方法
-
利用原语不允许被中断的特性
-
-
TestAndSet指令
-
利用硬件实现
-
-
swap指令
-
-
互斥锁
2.9信号量机制
-
信号量只能有初始化、P操作、V操作三种操作
-
wait原语和signal原语分别简称P、V操作
-
整形信号量表示系统中某种资源的数量
-
记录型信号量中value表示剩余资源数,对信号量进行一次P操作,意味着进程请求一个单位的该类型资源,需要对value--,当value<0表示该类型资源已经分配完毕,此时调用block原语进行自我阻塞,该机制遵循了让权等待
-
V操作反之
2.10信号量机制实现进程同步
-
在前操作后执行V操作,在后操作之前执行P操作
-
消费者问题
-
消费者从临界区消费产品,生产者向临界区生产产品,临界资源的互斥访问
-
生产者消费者共享一个初始为空,大小 n的缓冲区,有互斥信号量mutex实现对缓冲区的互斥访问,同步信号量empty表示空闲缓冲区的大小,同步信号量full表示产品的数量
-
-
多生产者消费者问题
-
抽烟者问题
-
读者写者问题
-
哲学家进餐问题
2.11管程--一种高级的同步机制
-
局部于管程的共享数据结构说明
-
对该数据结构进行操作的一组过程
-
对于局部于管程的共享数据设置初始值的语句
-
管程有一个名字
-
一个进程只有通过调用管程内的过程才能进入管程内访问共享数据
-
每次仅允许一个进程在管程内执行某个内部过程
-
引入管程的目的就是要更方便地实现进程互斥和同步,而管程的互斥性由编译器负责实现,程序员不用关心
2.12死锁
-
在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致个进程都阻塞,都无法向前推进的现象
-
死锁的必要条件,缺一不可
-
互斥条件,只有对必须互斥使用的资源的争抢才会导致死锁
-
不可剥夺条件,进程所获得的资源在未使用完之前,不能被其他进程强行夺走,只能主动释放
-
请求和保持条件:进程已经保持了至少一个资源,但是又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被堵塞,但又对自己已有的资源保持不放
-
循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求
-
-
何时发生死锁
-
对系统资源的竞争
-
进程推进顺序非法
-
信号量的使用不当
-
-
死锁的检测
-
用某种数据结构来保存资源的请求和分配信息
-
数据结构:两种结点
-
进程结点:对应一个进程
-
资源结点:对应一类资源,一类资源可能有多个
-
-
两种边:
-
进程结点->资源结点:表示进程想申请几个资源(每条边代表一个)
-
资源结点->进程结点:表示已经为进程分配了几个资源(没条边代表一个)
-
-
-
提供一种算法,利用上述信息来检测系统是否进入死锁
-
资源分配图可完全化简
-
-
-
死锁的解除
-
资源剥夺法,暂时挂起某些死锁进程,抢占它的资源,将这些资源分配给其他死锁进程,但是要防止被挂起的进程长时间得不得资源而饥饿
-
撤销进程法,强制撤销部分甚至全部死锁进程,并剥夺这些进程的资源。实现简单,单付出的代价大
-
进程回退法,让一个或多个死锁进程回退到足以避免死锁的地步,考虑进程优先级,已执行时间,进程使用资源,进程是交互式还是批处理式等
-
3.1内存
-
操作系统负责的内存管理
-
内存空间的分配与回收
-
提供某种技术从逻辑上对内存空间进行扩充
-
提供地址转换功能,负责程序的逻辑地址与物理地址的转换
-
内存保护
-
法一:在CPU中设置一对上下限寄存器
-
法二:重定位寄存器(基地址寄存器)和界地址寄存器(限长寄存器)
-
-
-
内存的覆盖技术(过时)
-
内存分为一个“固定区”和若干个“覆盖区”
-
需要常驻内存的段放在“固定区”中,调入后就不再调出(除非运行结束)
-
缺点:对用户不透明,增加了用户编程的负担
-
-
交换技术
-
内存空间紧张时,系统将内存中的某些进程暂时换出外存,把外存中某些已具备运行条件的内存换入内存(内存在内存与磁盘间动态调度)
-
PCB不会被交换
-
分为“对换区”(小)(连续分配方式)和“文件区”(大)(离散分配方式)
-
优先换出阻塞进程,可换出优先级低的进程,为了防止优先级低的进程被反复调入换出,有的系统考虑了进程在内存的驻留时间
-
3.2内存空间的分配
-
连续分配
-
单一连续分配
-
内存被分为系统区和用户区
-
只能有一道用户程序
-
实现简单,无外部碎片,可以采用覆盖技术扩充内存,不一定需要采取内存保护
-
只能用于单用户,单任务的操作系统,有内部碎片,存储器利用率低
-
-
固定分区分配
-
将整个用户空间划分为固定的分区
-
分区说明表包括对应分区的大小、起始地址、状态
-
实现简单,无外部碎片
-
用户程序太大,分区可能无法满足要求,降低了性能
-
会产生内部碎片,内存利用率低
-
-
动态分区分配(可变分区分配)
-
不会预先划分内存区,在进程装入内存时,根据进程的大小动态地建立分区
-
两种常用的数据结构
-
空闲分区表(包括区号、分区大小、起始地址、状态等)
-
空闲分区链
-
-
分区算法
-
首次适应算法
-
每次都从低地址开始查找,找到第一个能满足大小的空闲分区
-
空闲地址以地址递增的次序排列
-
-
最佳适应算法
-
按容量递增的次序连接,每次分配内存时按顺序查找空闲分区表,使得总能留下较大的一整片区域
-
缺点:每次都选最小的分区进行分配,会留下越来越多、很小的难以利用的内存块,因此会产生很多的外部碎片
-
-
最坏适应算法
-
优先使用最大的空间,以免留下太多难以利用的小碎片
-
容量递减的次序连接。。。
-
导致较大的连续空闲去区被迅速用完,之后如果有大进程到达,就没有内存分区可用了
-
-
邻近适应算法
-
每次分配内存时从上次查找结束的位置开始查找空闲分区链
-
可能导致无大分区可用
-
-
-
首次适应算法的效果反而更好
-
-
3.3非连续分配管理方式 分页存储
-
每一个分区就是一个页框=页帧=内存块=物理块=物理页面,每个页框都有一个页框号,从0开始
-
进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为页,与页框一一对应
-
内存空间分为“页框”,进程的逻辑地址空间分为“页”
3.4基本地址变换
-
在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的地址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中
-
检查页号(P)是否越界,查询页表,找到对应的页表项,确定页面存放的内存块号,用内存块号和页内偏移量得到物理地址并访问
-
页面管理中地址是一维的
-
通常使一个页框恰好能放入整个页表项。为了方便找到页表项,页表一般是放在连续内存块中的