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)是否越界,查询页表,找到对应的页表项,确定页面存放的内存块号,用内存块号和页内偏移量得到物理地址并访问
- 页面管理中地址是一维的
- 通常使一个页框恰好能放入整个页表项。为了方便找到页表项,页表一般是放在连续内存块中的