操作系统概述
操作系统的基本概念
操作系统的概念
操作系统是管理计算机硬件和软件资源的计算机程序。
计算机系统的构成: 用户 、应用程序、 操作系统 、 硬件。
计算机系统是一种 系统软件,功能有
1.与硬件交互;
2.对资源共享进行调度管理;
3.解决并发操作处理中存在的协调问题;
4.数据结构复杂,外部接口多样化,便于用户反复使用。
操作系统做了什么?
1.管理与配置内存;
2.决定系统资源供需的优先次序;
3.控制输入和输出设备;
4.操作网络与管理文件系统等基本事务;
5.提供一个让用户与系统交互的操作界面。
操作系统的目标
有效性
(管理系统资源)
1. 提高系统资源利用率 2.提高系统吞吐量
方便性
(方便用户使用)
可扩充性
(作为扩充机器)
开放性
(作为扩充机器)
操作系统的功能
OS作为计算机系统资源的管理者
这里的计算机系统资源 就是指的硬件
1.处理机(CPU)管理
2.存储器管理
3.I/O设备管理
4.文件管理
OS作为用户与计算机【硬件系统】之间的接口
1.程序接口
给应用程序使用
应用程序访问操作系统的接口 叫做系统调用
2.命令接口
给用户使用(例如 黑窗口cmd)
3.图形用户(GUI)接口
给用户使用
OS实现了对计算机资源的抽象
1.将具体的计算机硬件资源抽象成软件资源,方便用户使用
2.开放简单的访问方式,隐藏实际细节
例如 百度搜索 ,只需要用户输入搜索内容就能找到相关的事件
其实需要很多的细节来组成这个过程。
操作系统的特征
并发
同一时间间隔内执行和调度多个程序的能力
宏观上,处理机同时执行多道程序。
微观上,处理机在多道程序间高速切换(分时交替执行)
例如:先执行 程序1 20ms,再执行程序2 10ms ,再执行程序3 10ms.
再依次执行程序 1 、2、 3。
关注单个处理机同一时间段内处理任务数量的能力
相似概念:并行
并发:同一时间间隔(时间段)发生的事件数量
并行:同一时刻(时间点)发生的事件数量
例如:
餐厅打饭时,
并发指 目前餐厅内共有12人就餐(排队打饭的和打完饭的人)
并行指 同一时间点最多3人一起打饭
联系到前面的
OS的目标: 有效性 (提高系统资源的利用率 提高系统的吞吐量)
并发量可以提高 OS的有效性
并发的定义:关注 单个处理机 同一时间段内 处理任务数量 的能力
共享
系统中的资源供多个【并发执行】的应用程序共同使用
同时共享方式:同一时间段允许多个应用程序同时访问资源(例如 演唱会歌迷可以一起听歌)
互斥共享方式:允许多个应用程序在同一共享资源上进行独立而互不干扰的工作(例如 去公共电话亭打电话 只有等前一个人打完后一个人才能打电话)
并发和共享互为前提
共享要求OS同时运行多道程序,若只有单道程序运行那么不存在共享的可能。
并发难以避免的导致多道程序同时访问同一个资源,若多道程序无法共享部分资源则无法开发。
多道程序同时访问同一个资源: 例如 笔记本电脑上很多的应用程序在同时访问着唯一的CPU
虚拟
使用某种技术把一个物理实体变成多个逻辑上的实物
1.时分复用技术 ;2.空分复用技术
异步
程序执行的不可预知性
例如:程序什么时候开始执行、 程序因为什么而停止、程序执行所需的时间。
操作系统的发展与分类
手工操作阶段
批处理阶段
单道批处理
内存中只有一道程序
CPU需要等待I/O设备完成
多道批处理
提高CPU的利用率
提高内存和I/O设备利用率
增加系统吞吐量
平均周转时间长
无人机交互(从输入作业到作业输出不能进行其他操作)
单道批:作业输入、CPU执行、作业输出,前一个作业完成才能进行下一个
单道批串行运行
多道批:前一个作业输入完成进行CPU执行,这时就可进行下一个作业的输入。
多道批并行运行
分时操作系统
一台主机连接多个带有显示器和键盘的终端,同时允许多个用户通过自己的终端,以交互方式使用计算机,共享主机中的资源。
为什么需要分时系统?
1.人机交互
2.共享主机
3.便于用户上机
关键问题
及时接收
及时处理(作业提前进入内存,并且能和用户交互)
分时操作系统的特征
多路性:时间片轮转机制
独立性:用户彼此独立
及时性:用户能在短时间内获得响应
交互性:用户可以请求多种服务
分时操作系统的缺点
作业/用户的优先级相同,不能优先处理紧急任务。
实时操作系统
系统能即时响应外部事件的请求,在规定的时间内完成该事件的处理,并控制所有实时任务协调一致地运行。
应用需求
实时控制
实时信息处理
实时任务
周期/非周期性实时任务(根据周期性)
硬/软实时任务(根据截止时间)
硬实时任务指一定要在截止时间前完成 有硬性标准
软实时任务则反之
实时操作系统特征
多路性
独立性
及时性:以用户能接受的等待时间为准
交互性
可靠性:多级容错,保障系统和数据的安全
(多级容错指有多种出错后的解决办法 从而保障系统和数据的安全)
分时操作系统和实时操作系统的 及时性不同
分时操作系统的及时性:用户能在短时间内获得响应
实时操作系统的及时性:以用户能接受的等待时间为准
后者时间要求上更加严格 精确到毫秒及以下
微机操作系统
单用户单任务
多用户多任务
其他操作系统
网络操作系统
资源共享
远程通信
分布式操作系统
把任务分给多个计算机去完成,各计算机的优先级相同
分布性
并行性
操作系统的运行环境
用户空间 和 内核空间
分为 用户空间 和 内核空间
用户空间:
应用程序 、用户态 、非特权指令
内核空间:
内核程序、核心态、特权指令
应用程序和内核程序:
应用程序是操作系统非必要的程序,内核程序是必要的程序。
用户态和核心态:
CPU在执行用户空间的程序时是用户态,在执行内核空间的程序时是核心态。
(CPU中有个程序状态字在运行前者时是1,代表是用户态;后者是0,代表是核心态。)
非特权指令和特权指令:
在执行用户空间的程序时是非特权指令,执行内核空间时是特权指令。
操作系统的运行机制
时钟管理
计时:提供系统时间(例如 并发中需要计时来进行不同的作业)
时钟中断:比如 进程切换
中断机制
提高多道程序环境下CPU的利用率(例如 在等一个程序进行I/O时可以 进程切换到下一个程序)
外中断
中断信号来源于外部设备(被迫中断)
内中断
中断信号来源于当前指令(主动中断)
陷阱/陷入:由应用程序主动引发
例如
在执行一个应用程序时,执行到指令3 时需要进行一个其他操作,那么CPU就产生一个陷入指令,
从而来进行其他的操作。
陷入指令又叫房管指令、内陷指令。
陷阱/陷入 是良性的。
故障:由错误条件引发
CPU执行某个程序时,发现没有数据文件,那么此时出现内存缺页故障,CPU产生一个故障中断,当解决这个故障后程序还是会继续 执行接下来的指令。
终止:由致命错误引发
产生 地址越界、非法访问 的错误,会进行终止。
只要是中断,都会有对应的中断处理程序。
中断处理过程
1.关中断:CPU不响应高级中断请求
2.保存断点:相当于程序计数器PC 记录当前的中断处的指令位置
3.引出中断服务程序
引出指 获取该程序的内存地址
4.保存现场和屏蔽字
保存一下
5.开中断
6.执行中断服务程序
7.关中断
8.恢复现场和屏蔽字
9.开中断
原语
原语运行在内核空间
1.由若干条指令组成(说明原语是一个程序段)
2.用来完成某个特定功能
3.执行过程不被中断(说明原语具有原子性)
原语的底层实现利用的是 关中断 和 开中断
所以其 执行过程不被中断
原语(Primitive)和函数的区别
-
原语:原语是编程语言中最基本的操作,通常由编译器或解释器直接支持。它们是语言的核心功能,不能再分解为更小的操作。例如,赋值操作、算术运算符、逻辑运算符等都可以被视为原语。
-
函数:函数是由一系列语句组成的可重复使用的代码块。函数可以接受输入参数并返回一个结果。与原语不同,函数是由程序员定义的,可以根据需要进行扩展和修改。函数提供了一种模块化的方式来组织代码,并且可以通过调用函数来实现代码的重用。
总结来说,原语是编程语言中最基本的操作,而函数是由程序员定义的可重复使用的代码块。原语是语言的核心功能,而函数是对这些功能的封装和扩展。
系统数据结构
进程管理:作业控制块、进程控制块
存储器管理:存储器分配与回收
设备管理:缓冲区、设备控制块
系统调用:应用程序访问操作系统的接口
通过系统调用 CPU的状态从用户态切换到了核心态
1.由操作系统实现,给应用程序调用
2.是一套接口的集合
3.应用程序访问内核服务的方式
操作系统的结构
传统的操作系统结构
第一代:无结构OS
第二代:模块化结构OS:模块-接口法OS
(模块独立标准:高内聚、低耦合)
第三代:分层式结构OS
第四代:微内核OS结构
大内核就是个操作系统
微内核和直接跟硬件相关的操作放到一起
足够小的内核,只实现OS核心功能。
学到这里我发现这个屌操作系统真特酿的枯燥啊
进程管理
进程的概念
进程,是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行 资源分配和调度 的一个独立单位。
要点
1.进程是程序的一次执行
进程和躺在硬盘里的应用程序不同,进程是程序的执行。
2.进程是一个程序及其数据在处理机上顺序执行时所发生的活动
进程想要运行的话一定得加载到内存中才行。
3.进程是程序在一个数据集合上运行的过程
4.进程是系统进行 资源分配和调度 的一个独立单位(或者说 基本单位)
也就是说 OS以进程为基本单位来进行 资源得分配和调度
注:一个程序可以有多个进程
进程的结构
1.控制块(PCB)
进程的唯一标识
2.数据段
数据段存放原始数据和中间数据。
原始数据:应用程序本身带有的基本数据
中间数据:应用程序运行过程中可能产生的数据或者运行的数据
例如
计算器中 有加号 减号 称号 除号等 基本数据
在计算过程中 执行加减乘除的操作 那么就产生了中间数据
3.程序段
存放在文本区域可被多个进程共享
同一个应用程序的多个进程是共享程序段的
进程的特征
动态性:由创建而生,由撤销而亡
并发性:多个进程同时运行
独立性:独立资源分配
异步性:相互独立、互不干扰
线程的概念
什么是线程
1.进程的轻型实体,是一系列活动按事先设定好的顺序依次执行的过程,是一系列指令的集合。
2.是一条执行路径,不能单独存在,必须包含在进程中。(一个进程包含一个或者多个线程)
3.线程是OS中运算调度的最小单位。(进程是资源分配和调度的基本单位)
为什么引入线程?
提高OS的并发性
例如:
一个杀毒软件中,有木马扫描、垃圾清除、电脑体检等等功能。
打开这个软件的活动就是一个进程,而以上的功能便是线程。
如果一个进程里只负责木马扫描这一个功能,那么效率是很低的。
所以 线程可以提高OS的并发性。
线程的属性
1.轻型实体
2.独立调度和分派的基本单位
3.可并发执行
例如:一个进程里包含多个线程,这些线程都可以工作。
4.共享进程资源
同一个进程中的 多个线程 可共享该进程的资源。
进程和线程的区别
1.调度
(线程是调度的最小单元)
2.拥有资源
进程拥有资源的所有权,线程没有。
3.并发性
4.系统开销
5.地址空间和其他资源
6.通信
重点:
线程相对于进程,大大降低了创建、撤销和切换可执行实体的成本和难度。
在传统的操作系统中,拥有资源和独立调度的基本单位都是进程。
在引入线程的操作系统中,线程是独立调度的基本单位,进程是资源拥有的基本单位。
在同一进程中,线程的切换不会引起进程切换。在不同进程中进行线程切换,如从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换
线程的实现方式
用户级线程
内核级线程
线程控制块在用户空间即为用户级线程,在内核空间则为内核级线程。
用户级方式(多对一)
用户级方式中,TCB、数据段、程序段都在用户空间,线程库在用户空间。
用户级线程仅存在于用户空间中,此类线程的创建、撤销、线程之间的同步与通信功能,都无须利用系统调用来实现。(内核意识不到线程的存在,只知道用户空间中存在进程)
用户级方式优点
1.可以在不支持线程的操作系统中实现。(因为用户级方式中,内核默认只有进程没有线程)
2.创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多, 因为保存线程状态的过程和调用程序都只是本地过程。(线程管理的操作都在用户空间中执行,无需系统调用)
3.允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别
4.线程能够利用的表空间和堆栈空间比内核级线程多
5.不需要陷入/陷阱指令,不需要内核直接参与
内核级方式(一对一)
内核级方式中,TCB在内核空间,数据段和程序段在用户空间。
线程管理的所有工作由内核完成,应用程序没有进行线程管理的代码,只有一个到内核级线程的编程接口。
内核中的线程是并行的。
操作系统调度器管理、调度并分派这些线程。运行时库为每个用户级线程请求一个内核级线程。操作系统的内存管理和调度子系统必须要考虑到数量巨大的用户级线程。您必须了解每个进程允许的线程的最大数目是多少。操作系统为每个线程创建上下文。进程的每个线程在资源可用时都可以被指派到处理器内核。
内核线程驻留在内核空间,它们是内核对象。
有了内核线程,每个用户线程被映射或绑定到一个内核线程。
用户线程在其生命期内都会绑定到该内核线程。一旦用户线程终止,两个线程都将离开系统,这被称作”一对一”线程映射。
当某个线程希望创建一个新线程或撤销一个已有线程时,它进行一个系统调用
(某个线程想要进行线程管理的时候,先进行系统调用,请求指令,CPU状态由用户态切换到内核态,因为TCB在内核空间。然后再由用户空间的线程去执行)
内核级方式的优点
1.多处理器系统中,内核能够并行执行同一进程内的多个线程
2.如果进程中的一个线程被阻塞,能够切换同一进程内的其他线程继续执行(用户级线程的一个缺点)
3.所有能够阻塞线程的调用都以系统调用的形式实现,代价可观。
组合方式(多对多)
用户级方式和内核级方式的组合。
进程的状态
就绪
可以运行而未运行的状态
现在除CPU外,进程已经全部分配好了。
执行
阻塞
由就绪到执行,进程调度就是获得CPU的执行权的过程。
由执行到阻塞,需要执行一个I/O请求,那么该进程就进入了一个阻塞状态。有很多原因进入阻塞状态,因此也有很多阻塞队列来存放阻塞的进程。
由执行到就绪,如果没有别的请求那么执行完该进程后就进入了就绪状态,从就绪队列末尾插入该进程。
由阻塞到就绪,I/O请求完成或者是其他请求完成后,进入就绪状态。
创建
加载进程的结构:PCB、数据段、程序段
终止
进程控制
即OS对进程实现有效的管理,包括创建新进程、撤销已有进程、挂起、阻塞和唤醒、进程切换等多种操作。OS通过原语操作实现进程控制。
原语的概念
由若干条指令组成,完成特定的功能,是一种原子操作。
原语的本质是能完成特定功能的程序
原子操作就是不可再分的操作
原语的特点
原子操作,要么全做,要么不做,执行过程不会中断。
在内核态下执行,常驻内存。
是内核三大支撑功能之一。
操作系统的运行机制:时钟管理、中断处理、原语操作
创建原语:create;阻塞原语:block;唤醒原语:wake up;撤销原语:destroy
挂起与激活
为了系统和用户进行观察和分析进程。
挂起和激活 不是状态,他们是一个操作。
挂起原语:suspend
静止就绪:放外存,不调度
静止阻塞:等待事件
激活原语:active
活动就绪:等待调度
活动阻塞:等待唤醒
静止就绪、静止阻塞、活动就绪、活动阻塞,它们是状态。
由活动阻塞到静止阻塞:活动阻塞时占用内存却不运行程序,这时将其挂起,暂时解放这部分空间,并且将该进程放到外存。
由创建到挂起:可能创建个很大的东西使内存不够用,因此挂起,先放外存。
挂起就是从内存拿出来到外存,激活就是从外存拿出来放到内存。
挂起和阻塞的区别
挂起是一个主动的行为,会释放CPU,然后将该作业存到外存中。
当然,挂起的恢复即激活,也是一个需要主动进行过程。
阻塞是一个被动的行为,是在等待事件或资源时任务的表现,你不知道他什么时候被阻塞(pend),也就不能确切的知道他什么时候恢复阻塞。
阻塞后会将作业放入对应的阻塞队列,阻塞队列则是不同的事件或资源(如信号量)就有自己的队列。
处理机调度及调度层次
处理机调度
根据一定的算法和原则将处理机资源进行重新分配的过程
前提:作业/进程数远大于处理机数
目的:提高资源利用率,减少处理机的空闲时间
调度程序:一方面要满足待定系统用户的需求(快速响应),另一方面要考虑整体效率(系统平均周转时间)和调度算法本身的开销
处理机调度层次
高级调度/作业调度
把硬盘上的应用程序加载到内存中,创建成进程。
把后备作业调入内存。
只调入一次,调出一次。
中级调度/内存调度
将进程调入外存,条件合适时再调入内存(相当于挂起和激活)
在内、外存对换区进行进程对换
低级调度/进程调度(最常见)
从就绪队列选取进程分配给处理机
最基本的调度,频率非常高(相当于一个时间片完成)
处理机调度方式
剥夺式/抢占式调度
立即暂停当前进程,分配处理机给另一个进程。
原则:优先权/短进程优先/时间片原则
非剥夺/非抢占式调度
若有进程请求执行,等待直到当前进程完成或阻塞。
缺点:适用于批处理系统,不适用分时/实时系统。
处理机调度时机
进程运行完毕;
进程时间片用完;
进程要求I/O操作;(例如 从执行进入阻塞状态,这时调度处理机,重新分配资源)
执行某种原语操作;(例如 应用程序访问内核空间那么需要系统调用,执行原语操作)
高优先级进程申请运行(剥夺式调度)
处理机调度过程
1.保存镜像:记录进程现场信息
2.调度算法:确定分配处理机的原则
3.进程切换:分配处理机给其他进程
4.处理机回收:从进程收回处理机
处理机调度算法指标
CPU利用率:忙碌时间/总时间
系统吞吐量:完成作业数/总时间
周转时间:作业完成时间-提交时间
等待时间:作业等待处理机调度时间
响应时间:从提交请求到首次响应间隔
处理机调度算法
先来先服务(FCFS)
算法内容:调度作业/ 就绪队列中最先入队者,等待操作完成或阻塞
若阻塞后该作业会进入阻塞队列或者就绪队列,等待下一次调度。
算法原则:按作业/进程到达顺序服务(执行)
调度方式:非抢占式调度
适用场景:作业/进程 调度
优缺点:
有利于CPU繁忙型作业,充分利用CPU资源;不利于I/O繁忙型作业,操作耗时,其他饥饿。
饥饿指某一个作业长时间没有得CPU分配,导致很长时间的等待。
短作业优先(SJF)
算法内容:所需服务时间最短的作业/进程优先(执行)
算法原则:追求最少的平均(带权)周转时间
调度方式:SJF/SPF非抢占式
适用场景:作业/进程调度
在作业运行的过程中,可能出现阻塞。SRTN抢占式来解决选择哪个作业的问题。
SRTN抢占式根据 预估的该作业完成的总时间减去阻塞前运行的时间 的长短,从而来判断该让占用最短时间的作业运行(无论是否阻塞过,只要最短)
优缺点:
平均等待/周转时间最少;长作业周转时间会增加或饥饿;
长作业由于 短作业优先 的算法原则,会一直等待,导致周转时间增加。甚至周转时间过长,出现饥饿。
高响应比优先度调度(HRRN)
算法内容:结合FCFS和SJF,综合考虑等待时间和服务时间计算响应比,高的优先调度。
算法原则:综合考虑作业/进程的等待时间和服务时间
调度方式:非抢占式
适用场景:作业/进程调度
响应比计算:
响应比=(等待时间+服务时间)/服务时间(响应比大于等于1)
如果一个作业因为阻塞因此被放到就绪队列的最后面,那么其等待时间为0或者非常短,
因此响应比是大于等于1的。
只有当前进程放弃执行权(完成/阻塞)时,重新计算所有进程的响应比
长作业等待越久响应比越高,更容易获得处理机。
高响应比优先度调度,因为是响应比高的优先调度,所以避免了长作业出现等待时间过长甚至 饥饿。
优先级调度
算法内容:又叫优先权调度,按作业/进程的优先级(紧迫程度)进行调度
算法原则:优先级最高(最紧迫)的作业/进程先调度
调度方式:抢占/ 非抢占式(并不能及时获得执行)
非抢占式:如果前一个进程正在使用CPU,无论后面的进程优先级多高,都得等前面那个执行完。
适用场景:作业/进程调度
优先级设置原则:
静态/动态优先级;
静态是已经分配好的优先级,动态是管理员可以去主动分配的。
系统进程>用户进程;交互型进程>非交互型进程;I/O型进程>计算型进程.
交互型需要及时得到回馈所以优先级较高;
I/O型进程操作比较慢,让I/O型进程优先级高可以当适用I/O设备时,I/O设备可以及时执行,提高整体效率。
低优先级进程可能会产生“饥饿”
时间片轮转调度(RR)
算法内容:按进程到达就绪队列的顺序,轮流分配一个时间片去执行,时间用完则剥夺
算法原则:公平、轮流为每个进程服务,进程在一定时间内都能得到响应
调度方式:抢占式、由时钟中断确定时间到
适用场景:进程调度
作业调度是一次性操作,不需要考虑时间。
优缺点:
公平、响应快;适用于分时系统,不适应实时系统。
时间片决定因素:系统响应时间、就绪队列数量、系统处理能力
时间片太大,相当于FCFS;太小,处理机切换频繁,开销增大
多级反馈队列调度
算法内容:
设置多个按照优先级排序的就绪队列,优先级从高到低,时间片从小到大。
新进程采用队列降级法:
进入第一级队列,按FCFS、分时间片;如果没有执行完那么,该进程进入下一级队列,下下一级队列......
前面队列不为空那么不执行后续队列进程。
若队列中有的进程执行完了那么则释放CPU,如果没有执行完就进入下一级队列。
算法原则:集前几种算法优点,相当于 PSA + RR (优先级+分时间片)
调度方式:抢占式
适用场景:进程调度
优缺点:
对各类型相对公平;快速响应;
终端型作业用户:短作业优先;(该算法原则是 时间片从小到大,因此短作业容易先执行)
批处理作业用户:周转时间短
批处理作业用户一般同时执行很多的作业
长批处理作业用户:在前几个队列部分执行
因为采用分时间片原则执行,因此不会出现饥饿
进程间的协作
进程通信
概念:进程通信即进程间的信息交换
进程是资源分配的基本单位,各进程内存空间彼此独立
一个进程不能随意访问其他进程的地址空间
特点:共享存储;消息传递;管道通信
共享存储
基于共享数据结构的通信方式
1.多个进程共用某个数据结构(OS提供并控制)
2.由用户(管理员)负责同步处理
3.低级通信:可以传递少量数据,效率低
基于共享存储区的通信方式
1.多个进程共用内存中的一块存储区域
2.由进程控制数据的形式和方式
3.高级通信:可以传递大量数据,效率高
共享数据结构的通信方式 是 已经由管理员提供一个具体的数据结构,是提前设置好的。
共享存储区的通信方式 是 进程需要时那么进程便去向共享空间申请一块内存,然后加到自己的工作区。
共享存储的缺点:数据收发双方不可见,存在安全隐患。
消息传递
直接通信:点到点发送
发送和接收时指明双方进程的ID;
发送的消息一定要遵循某种格式。
每个进程维护一个消息缓冲队列。
如果没有这个消息缓冲队列,那么需要两个ID实时通信,一旦不实时可能造成丢失消息。
所以消息缓冲队列可以存消息。
间接通信:广播信箱
以信箱为媒介,作为中间实体;发进程将消息发送到信箱,收进程从信箱读取。
可以广播,容易建立双向通信链。
消息传递和共享存储模型类似,
但是消息传递通过原语实现,而共享存储通过共享数据结构和共享存储区来实现。
管道通信
管道
管道是一种用于在不同进程之间传输数据的通信机制。在操作系统中,管道可以将一个进程的输出直接连接到另一个进程的输入,从而使得这两个进程可以进行数据交流。管道可以用于实现进程间的数据传输和协作,提高系统的灵活性和效率。
管道和其他进程间通信的方式有以下几种区别:
管道是一种单向通信机制,数据只能在一个方向上流动,而其他进程间通信方式如消息队列、共享内存和信号量等可以支持双向通信。
管道只能在具有亲缘关系的进程之间使用,而其他进程间通信方式可以在任意进程之间使用。
管道具有固定的读端和写端,而其他进程间通信方式可以根据需要进行灵活的读写操作。
管道的数据传输是基于字节流的,没有明确的消息边界,而其他进程间通信方式可以支持消息级的数据传输。
管道的实现相对简单,只需要使用pipe函数创建一个管道即可,而其他进程间通信方式需要更复杂的操作。
用于连接 读/写进程的共享文件,pipe文件。
本质是内存中固定大小的缓冲区
半双工通信
同一时间段,只能单向通信,双工通信需要两个管道
同一时间段只能单纯进行读或者是写操作,
双工通信的两个管道可以实现读或者写操作同时进行。
以先进先出方式组织数据传输
通过系统调用read()/write() 函数来进行读写操作
管道这个文件是个固定的文件,读/写操作时,将读/写该文件的空间大小。
未满不读,已满不写,未空不写,已空不读,读后删除。
read()和write()操作是互斥的,这保证了两者不能在同一管道进行同时操作。
进程同步
协调进程间的相互制约关系,使它们按照预期的方式执行的过程。
互斥和同步
两种相互制约方式
间接相互制约方式(互斥):进程排他性地访问共享资源
直接相互制约方式(同步):进程间的合作,比如管道通信
前提
进程是并发执行的,进程间存在相互制约关系。
并发的进程对系统共享资源进行竞争
进程通信,过程中相互发送的信号称为消息或者事件
互斥的访问过程
访问过程:
当加锁时,可能有许多进程在临界区外等候,即进入阻塞。
那么他们将会进入一个阻塞队列,根据优先级或先来先服务等原则,
等待被唤醒。
1.进入区:尝试进入临界区,成功则加锁(lock)
临界区即临界资源、共享资源。
2.临界区:访问共享资源
3.退出区:解锁(unlock),唤醒其他阻塞进程
这里的唤醒,
可以唤醒一个进程,也可以唤醒所有进程,
若唤醒所有的进程那么它们就会进行争抢。
4.剩余区:其他代码
互斥访问的原则
空闲让进:临界区空闲,允许一个进程进入。
忙则等待:临界区已经有进程,其他进程等待(进入阻塞状态)。
有限等待:处于等待的进程,等待时间有限。
在进程同步中,有限等待通常是通过设置一个最大等待时间来控制进程等待的时间。当等待时间结束,而临界区的进程还未执行完毕时,可以考虑以下几种处理方式:
继续等待:如果临界区的进程执行时间较长但可预测,可以选择继续等待一段时间,再重新检查临界区是否可用。这种方法适用于能够容忍一定等待时间的情况。
优先级调整:可以考虑提高等待进程的优先级,以确保它在临界区进程执行完毕后尽快得到执行。通过调整优先级,可以提高等待进程的调度权重。
超时处理:当等待时间超过预定的最大等待时间时,可以选择终止等待进程或执行一些特定的错误处理操作。这可以防止长时间等待导致系统资源浪费或阻塞其他进程。
资源分配策略:优化临界区的执行时间,通过减少临界区的代码量或优化算法来减少临界区的执行时间,从而减少其他进程的等待时间。
需要根据具体情况选择适当的处理方式,以确保系统的正常运行和资源的有效利用。
让权等待:等待时应让出CPU执行权,防止“忙等待”。
忙等待就是 原地踏步 ,虽然在执行但是不前进。
软件实现互斥的方法
单标志法:违背“空闲让进”
用到一个公共变量turn,作为单标志。
当turn为1则允许P1进程访问资源,turn为0则允许P0进程访问资源。
P0和P1其中一定有一个在临界区访问资源而另一个在等待,
当turn为1则P1进程访问临时区,此时P0进程的while循环是死循环,所以P0进程一直等待,
当访问结束后turn变为0,接下来P0进程可访问临界区。
弊端:
如果所有P0进程都已经执行完毕,此时turn变为1,然后执行P1进程在临界区执行完毕后turn变为0.
可所有的P0进程都已完毕,那么turn将一直保持为0,即P1进程不会再在临界区执行。
这就违背了“空闲让进”的原则
双标志法先检查:违背“忙则等待”
设置两个标志位flag[0] 和 flag[1],
P0进程访问临时区前先检查P1进程是否在访问,反之同理。
弊端:
如果两个标志位都为false的话,因为先检查的原因,
两个while()循环都不成立,这样就会导致P0和P1两个进程同时进入临时区。
双标志法后检查:违背“空闲让进”、“有限等待”
P0进程要进入临界区前,先将flag[0]置为true,再检查临界区是否有进程在执行,P1进程同理。
有可能出现 flag[0] flag[1] 均为true 的状态,此刻两者都进入不了临界区,因此违背空闲让进。
而两者的while死循环违背了优先等待原则
皮特森算法:违背“让权等待”、会发生“忙等”
皮特森算法不会出现两个进程同时死锁的情况。
举例说明:
当P0进程执行到while循环时,若没有其他进程执行则P0直接进入临时区。
若P1此刻执行到了第一行,那么P0陷入循环;因此发生“忙等”。
P1接着执行第二行,此刻P0中turn变为0,P0进入临时区;
等P0执行完,P1再接着执行,while条件不成立,P1进入临时区执行.
在P0陷入while死循环时,仍在等待P1执行,不会让出CPU,因此违背“让权等待”。
硬件实现互斥的方法
中断屏蔽:关中断/开中断
禁止一切中断,CPU被执行完临界区之前不会切换。
关中断影响效率。
不适用于多处理机,无法防止其他处理机调度其他进程访问临界区。
关中断后,该进程所占处理机不会被调度,但其他处理机仍可以被调度,运行其他进程来访问临界区。
只适用于内核进程(该指令运行在内核态)。
关中断、开中断,属于低级指令(特权指令),只能在内核态进行。
自由度不是很高,需要的权限较多。
TS指令
读出标志(即lock) 并设置为true,返回旧值。(原子操作)
读出标志 设置值 返回值 的一系列操作为原子操作
原子操作不会被中断,不会被插入。
违背“让权等待”会发生忙等
当TestAndSet返回值为true时,代表临时区有进程,那么此刻等待的进程执行while死循环,
仍继续等待,因此发生忙等。
Swap指令:违背“让权等待”
交换两个变量的值(原子操作)
lock表示临界区是否被加锁,
若lock为true 则交换后 old仍为true,陷入死循环。
等其他进程出临界区后,lock为false,交换后old为false。
此刻,该进程可进入临界区执行。
多处理机进程执行时,可能会担心是否会数据紊乱?
不用担心,因为这是个原子操作,中间不会打断。
虽然lock是公共变量,但只有前一个进程结束后下一个进程才能访问lock。
信号量
信号量的概念
信号量机制:
PV操作:
P操作:wait原语,进程等待
V操作:signal原语,唤醒等待进程
wait和signal都是原语操作,不用担心被中断。
信号量就是指可用资源数量。
例如公共停车场,车停满后,只有每次开出一辆车另一辆车才能进入。
停车场可用停车位就是信号量
整型信号量:违背“让权等待”,会发生忙等。
还是例如停车场,如果里面车不走,外面车就一直等着,发生了忙等。
信号量的工作机制
记录型信号量:进程进入阻塞状态,不会忙等。
当有进程在临时区外等待时,让他们进行wait()申请资源.
然后令信息量(剩余可用资源数量)减1,如果剩余资源数量小于0,
那么证明 等待进程数大于信息量,此时阻塞等待的进程。
有进程执行signal时,先value++,让出一个信息量。
然后反复执行signal(),唤醒所有等待的进程,让这些进程去争夺那个唯一的空闲资源。
记录型信号量和整型信号量的区别:
记录型信号量有一个等待缓冲队列,可将等待的进程放入其中,
防止发生忙等情况,取而代之的是将进程直接阻塞。
分析进程同步和互斥问题的方法步骤
1.分析关系
进程的数量、进程间的同步或互斥关系、前驱关系;
2.整理思路
根据进程的操作流程确定P操作、V操作的大致顺序
3.设置信号量
根据前两步分析和整理,设置信号量初始值。
管程
即“管理进程”,用于实现进程同步的工具。是由代表共享资源的数据结构和一组过程(进行PV操作的函数)组成的管理程序(封装)
在并发编程中,多个线程同时访问共享数据可能会引发竞态条件和数据不一致等问题。为了避免这些问题,可以使用管程来管理共享数据的访问。
管程还提供了对共享数据的互斥访问机制,保证同一时间只有一个线程可以访问共享数据,从而避免了竞态条件的发生。
一次只能有一个进程/线程来访问管程
管程的组成
1.管程名称
2.局部于管程内部的共享数据结构
管程中的共享数据是用来实现线程间的通信和数据共享的。
局部于指的是私有,不可被公共访问。
3.对该数据结构操作的一组过程(函数)
进程需要通过该过程才能访问共享数据。
4.管程内共享数据的初始化语句
总而言之,管程就是管理进程同步的工具。
管程的基本特性
操作系统中不仅仅只有一个管程。
1.是一个模块化的基本程序单位,可以单独编译。
并非是有进程才有管程,管程可独立存在并编译。
2.是一种抽象数据类型,包含数据和操作。
3.信息掩蔽,共享数据只能被管程内的过程访问。
管程中的条件变量
条件变量/条件对象
这些条件在管程的内部,进程/线程访问管程时,遇到这些条件后,可能因不满足而发生阻塞。
进入管程的进程可能由于条件不满足而发生阻塞;
此时进程应该释放管程以便其他进程调用管程;
进程被阻塞的条件有多个,移入不同的条件队列。
进程被移入条件队列后,应该释放管程。
因不同条件而发生阻塞的进程,放入相对应的条件队列进行等待;
唤醒的时候也在该条件队列唤醒,然后需要重新获取管程。
死锁
死锁的概念
死锁:多个进程由于竞争资源而造成的阻塞现象,若无外力作用,这些进程将无法继续推进。
相似的概念:饥饿
等待时间过长给进程推进和响应带来明显影响,但是不会无法前进。
死锁产生原因:系统资源的竞争、进程推进的顺序非法。
进程推进的顺序非法,类似于前面的进程互斥的 双标志法代码执行顺序不理想,导致出现忙等的情况。
死锁产生的必要条件
互斥条件:共享资源的排他性访问
不剥夺条件:访问时,该共享资源不会被剥夺
请求并保持条件:保持当前资源时,请求另一个资源。
当前资源不够满足现在的进程,于是进程在保持当前资源时,请求另一个资源。
当另一个资源在使用或者现在的进程不能满足管程的条件时,现在的进程就进行等待。
而后面的进程想要使用当前资源那么也就会等待,导致出现一连串的等待,即死锁。
循环等待条件:存在共享资源的循环等待链
例如:
a进程持有A资源,却在等待B资源;b持有B资源却等待A资源。
这样相互等待形成循环,称为循环等待。
死锁的预防
破坏互斥条件
1.将只能互斥访问的资源改为同时共享访问; 2.将独占锁改为共享锁;
并不是所有的资源都可改为可共享的资源
共享锁就是当缓冲队列达到最大后就锁住,不让其他进程再进入缓冲队列。
其实 信号量如果等于1那么就是互斥锁,信号量大于1就是共享锁。
例如:
如果P0 P1同时访问打印机时,那么打印出来的东西,乱七八糟。
而改为同时共享资源后,加了个缓冲,将P0 P1 放入队列,再依次打印,实现了宏观上的共享。
破坏不可剥夺条件
1.请求新资源无法满足时必须释放已有资源;
2.由OS协助强制剥夺某进程持有的资源;
缺点:实现复杂,代价高; 此操作过多导致原进程任务无法推进。
去请求新资源时必须释放已有资源,但有可能该进程还未执行完,导致需要再次申请该资源,影响操作系统的吞吐量。
破坏请求并保持条件
1.进程开始运行时一次性申请所需资源
缺点: 资源浪费 、进程饥饿。
资源浪费:一次性占用所需资源,在执行前面的资源时后面的资源闲置,降低资源利用率
进程饥饿:某进程一次性占用所需资源,导致此后的进程等待,造成进程饥饿。
2.阶段性请求和释放资源
如果用完了当前的资源那么就申请下一个资源,并把当前资源释放掉,阶段性申请资源并非一次性申请资源。
缺点:可能申请到下一个资源不及时。
破坏循环等待条件
对所有资源现行排序,按序号申请资源。
(申请时先低后高,释放时先高后低。)
这样可以确保申请时恰好有空闲资源
缺点:
对资源编号应该相对稳定,限制新设备增加;
进程使用资源的顺序可能与系统编号顺序不同。
限制用户编程。
死锁的避免:安全性算法
系统安全状态
安全状态一定不会出现死锁;不安全状态可能出现死锁。
银行家算法
系统预判进程请求是否导致不安全状态?是,则拒绝;否,则答应。
例如:
操作系统分配资源,按照进程最大需求资源数量 和 自己拥有资源数量,
按照一定顺序和一定量的分配,每次分配前后都需要进行安全性算法,
决定是否进行分配。
死锁的检测与解除
死锁检测
1.需要一种数据结构,保存有关资源的请求和分配信息
2.提供一种算法,利用这些信息检测是否形成了死锁
资源分配图(G=(N,E));
两种资源、两种节点。
死锁定理(死锁状态的充分条件)
当且仅当此状态下资源分配图是不可完全简化的;简化过程相当于“拓扑排序”。
简化过程为 释放那些 不阻塞而又不是孤立点的进程。
阻塞:进程的分配边和请求边使共享资源分配不足,即为阻塞。
孤立的:既没有请求边也没有分配边
例如:图中P0分配边和请求边都不会使R1 R2两个共享资源分配不均,这个便可以被释放。
而P1使R1分配进程不足,P1则阻塞。
(这是简化后的图)
如果存在不可完全简化的图那么即产生了死锁
死锁解除
资源剥夺
挂起死锁进程,剥夺其资源,将资源分享给其它(死锁)的进程。
撤销进程
撤销进程是一项潜在危险的操作,原因如下:
数据丢失:撤销进程将导致正在进行的任务被终止,而未保存的数据可能会丢失。这可能会对正在进行的工作造成损失,特别是对于那些需要长时间运行或对数据进行复杂处理的任务。
系统不稳定:撤销进程可能会导致系统不稳定或崩溃。进程之间通常存在相互依赖关系和资源共享,当一个进程被强制终止时,可能会对其他进程或系统资源造成影响,导致系统不可预料的行为。
数据一致性问题:撤销进程可能导致数据一致性问题。如果进程在处理关键数据时被中断,可能会留下未完成的操作,导致数据处于不一致的状态,这可能会对后续的操作产生负面影响。
安全性问题:撤销进程可能引发安全性问题。某些恶意软件可能会利用进程撤销来破坏系统或窃取敏感信息。此外,如果进程正在执行敏感操作,如数据库事务或网络连接,撤销进程可能会使系统容易受到攻击。
进程回退
进程回退指让进程释放已经执行的部分
例如:已经执行了80%的进程让它回退到50%
回退到足以避免死锁的地步,需要记录进程历史信息,设置还原点。
进程回退内存需要比较大
内存管理
准备工作
存储器的多层结构
CPU寄存器:寄存器
主存:高速缓存、主存储器、硬盘缓存(狭义的主存就只是主存储器)
辅存:固定磁盘、可以的存储介质
进程挂起中把进程放到的外存指的是硬盘缓存, 硬盘缓存属于固定磁盘的一部分。
进程运行的基本原理
从用户程序到进程
从用户程序到进程:
编译 -> 链接 -> 装入
首先是编译,用户将自己写的代码进行编译,编译成目标模块;
然后和一些库进行封装、整合,放入链接程序,链接程序再装入模块;
最后再装入内存。
编译
编译属于用户的操作,并不属于操作系统。
链接
静态链接
如果程序比较小,可以在装入前就完成链接,然后装入。
装入时动态链接
程序比较大,可以在链接时完成一部分,再在装入时再链接另一部分,然后一起装入。
运行时动态链接
程序太大,当运行时发现模块缺失,这时会出现一个缺页中断,需要从磁盘加载过来。
程序运行时由链接程序进行封装打包,装入到内存中。
装入
绝对装入
可重定位装入
绝对装入是单道程序的装入,找到内存中空闲的物理地址,一次性装入。
可重定位装入是多道程序的装入,如果原本打算装入的初始地址被占用了,那么就找一块其他地址重新装入,只不过初始地址和最终地址都需要再次定位。
绝对装入和可重定位装入都是一次性装入。
动态运行时装入
在程序运行前先装入一部分,然后在运行过程中由程序动态申请再次进行装入。
可能会出现一个程序的程序和数据分配在不连续的区域
如果应用程序大小 大于 内存剩余空间大小,这时需要内存扩充。
内存扩充的两个方式
覆盖
内存中有些部分可以被覆盖。
动态运行装入时空间不够用的话,可以将内存上一部分旧程序覆盖,然后再次装入时又可以将前一部分覆盖掉。
交换
交换是从磁盘上额外开辟一块空间即硬盘缓存,将内存中不活跃的程序交换到外存,然后空余出来的内存空间给当前需要空间的程序使用
两个细节
逻辑地址和物理地址
如果内存中地址从0开始,程序中的地址和内存中的地址一 一对应,那么称为绝对地址。
物理地址是指实际的内存存储位置,而逻辑地址是相对于进程而言的虚拟地址。
在程序执行时需要经过逻辑地址到物理地址的转换才能访问内存中的数据或指令。
内存保护
即保护该程序所占的内存空间。
需要记录物理地址的范围,然后进行内存保护。
可以记录两个物理地址,一个最大一个最小。
也可以记录一个最小的物理地址和一个最大的逻辑地址。
连续分配管理方式
单一连续分配
系统区首先存入,因此占低地址;用户区则占据高地址部分。
单一连续分配,顾名思义 用户进程以连续的方式从用户区开始分配内存,一次只有一个进程作业。
内部碎片就是已经被分配出去(明确指出属于哪个进程)却不能被有效利用的空间。
外部碎片就是还没有被分配出去(不属于某个进程)但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
优点:
实现简单;无外部碎片;不一定需要内存保护
缺点:
只能用于单用户、单任务OS;有内部碎片;存储器利用率低。
单一连续分配是将整个用户区分配给一个进程,进程一般用不完整个用户区的内存空间,因此会产生内部碎片,由此根本不存在外部碎片。
不一定需要内存保护 因为是单个进程不会有额外的进程来干扰用户进程所占内存区域,但是系统区和用户区不一定有严格的物理界限,可能会出现用户区去影响系统区。
固定分区分配
固定分区分配,静态分配内存,提前把内存进行分区,无论区域大小是否相同。
优点:实现简单;无外部碎片。
缺点:较大用户程序时,需要采用覆盖降低性能;会产生内部碎片,利用率低。
较大用户程序时分区内存大小可能不够,因此需要覆盖;而较小用户程序时,分区内存可能太大又会产生内部碎片。
动态分区分配
当进程装入内存时,根据进程的需要动态建立分区。
动态分区分配在内存空间为空时,会动态按照每个程序大小分配空间,可程序结束释放空间后,这些被占用过的空间就会被记录为分区。(并不是主动为内存空间进行的分区)
于是便有了 空闲分区表 或者 空闲分区链
怎样记录内存的使用情况?
动态分区分配需要一个 空闲分区表
选择哪个分区给新进程?
首次适应算法:从低地址开始查找合适空间
从低地址处开始查找,查找到满足大小的空间就把用户进程放入。
最佳适应算法:优先使用最小合适空间
按照空间从小到大的顺序查找,找到满足大小的后放入。
最坏适应算法:优先使用最大合适空间
按照空间从大到小的顺序查找,找到满足大小的后就放入。
更适合较大的程序来使用。
临近适应算法:从上次查找处向后查找
同首次适应算法一样,只不过这个是从上次查找处开始向后,而不是最低地址处开始。
已使用的分区怎么回收?
回归规则:
回收后相邻空间要合并(前提是相邻空间是空闲状态);更新空闲分区表/链的记录。
缺点是会产生外部碎片。
外部碎片:就是还没有被分配出去(不属于某个进程)但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
外部碎片产生是因为新的应用程序按照空闲分区表被分配到对应的分区,但新分区内存空间较大,剩余那部分小的分区利用不了就成为了外部碎片。
非连续分配管理方式
基本分页存储管理方式
分页的意思就是把内存分成大小相等的分区
基本分页存储管理方式的本质是固定分区管理方式
只不过基本分页存储管理方式的页框非常小,这样可规避外部碎片的产生。
但是会产生内部碎片,因为程序大小估计不到具体。
给物理地址分页同样给逻辑地址也要进行分页,两种页数相等。
而想要将逻辑地址的页和物理地址的页想要联系在一起,就需要一个页表。
页表记录逻辑地址的页和物理地址块的页,找到对应关系。
页表中的页号和块号并非是一 一对应的,因为这时非连续分配方式。
怎么实现逻辑地址为1024的空间 +1?
需要计算逻辑地址为1024的空间在逻辑地址的哪个页上,
然后根据页表找到对应物理地址的页,
然后取出对应物理地址的块的数据进行+1,最后再放进去。
基本地址变换机构
物理地址=(页号->块号)+偏移量
页号P= 逻辑地址A / 页面长度L
偏移量=逻辑地址A % 页面长度L
P=A>>12 ; W=A & 4095
例:
这里用位运算 A右移12位即 A除以4K(4098), A&4095即用位运算 取模
特点
整个过程是逻辑地址通过CPU(先进行检查页号判断是否越界中断),再从页表寄存器中读取页表位置然后使用页表查询对应关系,最后找到物理地址并进行操作。
页表寄存器中存放页表,可通过该寄存器找到页表,因为页表本质上是个数组(数组具有连续性),可根据此找到对应的物理地址。
1.页式管理中地址空间是一维的
页表实际上是一个数组,页号和块号是对应的关系。
2.每次访存需要地址转换,必须足够快
硬件可以实现这个要求
3.页表不能太大,会降低内存利用率
页表存放在PCB中,太大会影响进程。
具有快表的地址变换机构
工作过程
直接将 逻辑地址对应的页号 与 快表的页号 比较
匹配成功,取块号+偏移量形成地址
匹配失败,访问主存页表,并同步到快表。
仅仅读取一个物理地址需要访问两次内存,效率比较慢,因此有了快表。
快表就如同cache一样,快表位于高速缓存中。
快表中存放页号和块号,原页表也可称为慢表。
首先从慢表中读取页号、块号后,最后内存再读取物理地址。同时会将慢表中的页号、块号,存入高速缓存中的快表中。
如果下次访问的页号在快表中存在,那么CPU无需再访问内存,直接访问高速缓存中的快表进而获取物理地址。
但快表的内存空间有限,同样,位于高速缓存中的快表存在一定命中率。
而且,快表中的页号并不是连续的(慢表中的是连续的),因此,快表是个二维的。
综上,快表位于高速缓存、快表存在命中率、快表是二维的。
两级页表
页表中最大的条目为 1M,块号一个占四个字节,因此页表中最大空间为4M.
两级页表就是建立一个 页目录表,再根据页目录表的条目创建二级目录,进行映射查询。
过程:
逻辑地址分为三部分;(页目录表的页号为目录,块号为了映射二级页表的编号,二级页表的页号为真正的逻辑地址)
从PCB中读取页目录表起始地址;
根据一级页号查出二级页表位置;
根据二级页号查内存块号,加偏移量计算物理地址。
例如:
寻找逻辑地址为1024的物理地址(在此以32位举例)
一级页号由前十位决定,二级页号由中间十位决定,页内地址由后十二位决定。
写出1024的32位二进制,
1.将1024的32位二进制 右移22位,取得一级页号为多少,据此得出二级页号的位置
2.将1024的32位二进制 左移10位、右移22位,得到二级页号的逻辑地址
3.找到块号地址再加上偏移量即得物理地址。
基本分段存储管理方式
分段式存储管理方式是按照程序的逻辑结构进行分段的。
分段
段表
段表是二维的,段号映射段长和基址。
地址变换机构
段的共享与保护
例如 2号段被共享,那么只需要将2号段的信息添加到段表中即可。
同一物理段被多个子程序共享,只需将该物理段的信息添加到段表中。
分页是把物理磁盘按固定大小去区分,分段则是把应用程序进程按照不固定大小去划分。
分页和分段存储管理方式的区别
1.页->物理单位, 段->逻辑单位
2.分页->一维地址空间,分段->二维地址空间
页表大部分放在内存,段表大部分放在段表寄存器
分段更容易信息共享和保护
段页式存储管理方式
分页会产生内部碎片,分段会产生外部碎片。
.
虚拟内存管理
概念
内存和外存之和称为虚拟内存
具有请求调入和置换功能,从逻辑上对内存容量加以扩充的一种存储系统
局部性原理
时间局部性
空间局部性
时间局部性:短时间内操作同一数据
空间局部性:短时间内访问同一个空间范围
局部性原理催生的是缓存技术
CPU寄存器:寄存器
主存:高速缓存、主存储器、硬盘缓存
辅存:固定磁盘、可移动存储介质
虚拟内存的特性
多次性、对换性、虚拟性
多次性:多次动态装入
对换性:类似于挂起操作
虚拟性:内存和外存之和称为虚拟内存
虚拟内存的实现
请求分页管理方式
页表机制
内存块号:如果当前页已经调入内存那么便有内存块号。
状态位:当前页如果已经调入内存那么状态位为1,反之为0;
访问字段:用于记录一段时间内页被访问的次数,例如:13即13次,8即8次
(可以用于页面置换算法的参考)
修改位:1表示修改过,0表示未修改过
外存地址:当前页在外存的地址(本身进程在内存中),在地址变换时很需要。
缺页中断机构
缺页:程序执行时,要访问的页在内存中不存在。
类似于中断机制的缺页故障中断
例如:
把缺失的页面调入内存
如果想要把在外存的x号块放到内存的a号块位置,但是a号块位置不存在。
那么就需要进行缺页故障中断,这时通过中断将外存x号块上的程序加载到内存的空闲号块上面。
当然,内存号块、状态位等等都会被加载上去。
把不需要的页面调出内存
例如调出从内存c号块到外存的z号块,然后将c号块置空。
即使该页被修改过也没关系
地址变换机构
流程:
1.请求调页,判断是否在内存
运行中发现页并不在内存中,此时从外存磁盘中调入内存
2.可能需要页面置换.
当内存空间不够用,把一些不太需要的页调出内存放到外存。
3.新增/修改页表项
页调出时,需要把页表项里的内存块号、状态位等等清除掉;
页调入时,需要把一些页表项添加上。
4.热点页表项同步到快表
把一些经常访问的页表项同步到快表(局部性原理),新调入的页同步到快表。
页面置换算法
最佳置换算法OPT:保障最低缺页率
每次选择淘汰最不可能再次被使用的页面
(最不可能 这个程度无法预知,所以该算法无法实现)
先进先出置换算法FIFO:保障顺序上的公平
每次选择淘汰最早进入内存的页面
(按顺序进行淘汰是不合理的,因为访问率高的页面并不是依照顺序来排序的)
最近最久置换算法LRU:保障时7间和距离上的公平
每次选择淘汰 最久 最近 未使用的页面
(需要额外建立一个字段存放再次访问该页经历的时间,需要硬件支持,开销大)
时钟置换算法NRU:保障性能和开销均衡
为页面设置访问位(0/1),并链接成循环队列,开始全置为1,进程访问后置为0,淘汰访问时为0的页。
访问每个页后置位0,如果正在访问则为1.
每轮至少淘汰一个页面。违背“局部性原理”
改进型时钟置换算法:额外考虑是否修改保障最少I/O操作
增加修改位(0/1),第一轮找(0,0),第二轮找(0,1)并修改访问位为0;
第三轮找(0,0),第四轮找(0,1)并修改访问位为0..........
(1,0)最近访问过但未修改过,(1,1)最近访问过且修改过
(0,0)最近没访问过也未修改过,(0,1)最近没访问过但以前修改过
页面分配策略
驻留集大小
驻留集:驻留在主存的页面数
1.分配空间小,进程数量多,CPU时间利用效率就高
2.进程在主存中页数少,错页率就高
3.进程在主存页数多,错页率无明显改善
分配策略
1.固定分配局部置换
2.可变分配局部置换
3.可变分配全局置换
固定分配:OS给进程分配一定的内存空间,该进程内存空间不可增加
可变分配:OS给进程分配一定内存空间,如果不够用,该进程可向OS申请
局部置换:如果页数不够用,该进程可以将自己的页数调入调出
全局置换:页数不够用,可向OS申请多余的页数
调入页面的时机
调入策略
预调式策略
一次性调入若干相邻页面(多用于进程首次调入)
进程首次调入时,一般由程序员主动指出关于创建进程的核心文件,其中相关联的关键的函数和类,被调入。
请求调页策略
运行时发现缺页调入(I/O开销较大)
出现缺页问题,那么需要从外存磁盘调入页面,此时需要的I/O开销较大
从何处调页
外存分为对换区和文件区
对换区的地址空间为连续的,文件区的是离散的。
OS系统如果有足够空间,
创建进程时,一般先加载那些核心的页面到内存中,一些其他程序可加载到对换区。
一般不会被修改的文件,例如只有功能没有数据,有换出需求时,可不必换出直接从内存中删去即可(因为没有数据不会产生影响,下次需要输入时直接从外存的文件区读取即可),
这样少了一次I/O操作。
UNIX方式
跟文件有关的程序默认放置在文件区,从内存中换出时,放在对换区,下次再从对换区换入。
文件管理
文件的概念
定义
文件:以计算机硬盘为载体的存储在计算机上的集合
属性
文件不仅能记录信息还能存储属性
描述文件的一组信息,比如:名称、标识符、类型、大小、位置、保护、时间、日期和用户标识等等。
基本操作
创建文件、读文件、写文件、文件重定位、删除文件、截断文件、打开与关闭。
文件的结构
文件的逻辑结构
无结构文件(流式文件)
以Byte为单位;没有具体结构;采用穷举方式搜索(从第一个字节到最后一个字节挨个识别)
例如这种纯文本文件就是流式文件
我们自己写的代码文件也是无结构文件(流式文件)
有结构文件(记录式文件)
顺序文件
变长中,每有一个数据就算是一个记录;定长中,每一行是一个记录。
变长中,无法快速定位某个记录;定长中,无法快速增删记录。
索引记录
可以快速定位,也可以实现变长。
实现变长的方法:
1.预先建立一个大索引表,需要添加数据就直接往里添加;
2.等到现有索引表满后,再申请一个更大的索引表,将现有数据复制到大的索引表里面。
索引顺序记录
一个索引表项对应一组记录。
如果索引表过多的话可以通过 顶级索引表来实现,空间换时间。
直接文件或散列文件
用key和value的映射关系实现
文件的目录结构
文件控制块FCB
每一个条目都是一个FCB, 一个FCB条目可能是“文件”也可能是“目录”。
基本信息
文件名、类型、物理位置就属于基本信息
存取控制信息
存取权限属于存取控制信息
使用信息
创建时间、修改时间等属于使用信息
索引节点
根据文件名建立一个索引表。
可通过文件名找到索引节点指针然后再访问文件名以外的信息
目录结构
单级目录结构不允许创建同名文件,而我们又有需要创建同名文件的需求。
此时需要多级目录结构。
多级目录结构就是一个多层次的树型结构
此时想要进行共享,
那么多个用户创建指向一个目录的连接,再创建一个计数器,
每当有用户去共享那么计数器就++,每当不想共享时那么就把连接删去且计数器- -。
当没人再访问计数器时,就会把此目录及其子目录删掉。
文件共享
硬链接(索引节点)
根据文件名去建立一个索引节点表,索引节点指针指向索引节点,索引节点记录了文件的基本信息。
只不过索引节点需要加一个计数器,当有用户访问时就++,有用户停止访问就- -且把链接删掉。
软链接(符号链)
需要创建一个新的文件来记录目标文件的地址,通过此来访问目标文件的基本信息。
注意:如果我们删去新创建的文件,这对目标文件并没有任何影响。
区别:
硬链接只是加了个索引节点指针,而软链接却新建了个文件和索引节点指针,所以后者占空间更多一点。
硬链接的效率比软链接要高。
硬链接通过索引节点指针直接访问文件,而软链接需要先读取目标文件的地址再创建新文件去访问,但软链接的访问方式更安全。
文件保护
口令保护
在索引节点这里进行口令加密。
加密保护
对目标文件进行加密,即使绕过索引节点也不行,需要解密才能查看。
访问控制
针对某个用户进行访问控制
文件系统的层次结构
用户如果想要访问文件,一定通过系统调用。
用户调用接口:应用程序通过系统调用访问操作系统内核的功能
文件目录系统:使用FCB,去查看、管理、调用下一级。
存取控制模块:存在一些软件程序,控制访问权限。
逻辑文件系统与文件信息缓冲区:
文件的存取动作不仅仅是从逻辑到物理,而是需要一个文件信息缓冲区。
物理文件系统:物理设备
辅助分配模块;
设备管理程序模块;
例如:
我们双击打开一个文件就是用户调用接口,访问文件名之后我们只是访问到了索引节点,
如果存取控制模块的访问权限通过后,我们才算真正地访问文件。
而现在只是逻辑地址,在 逻辑文件系统与文件信息缓冲区 这里转为物理地址,
(这里操作的是这个文件并不是文件里面的数据)
转为物理地址后由磁盘设备进行操作,再读到缓存然后进入内存。
CPU不能直接对磁盘进行操作。
文件的目录
目录的实现:线性列表;哈希表。
线性表中的链表和数组在访问一个文件时,都需要从头开始遍历访问。
而哈希表可以提升效率。
文件名和索引进行哈希算法来产生映射,从而可以快速定位索引。
当然两个不同的文件名进行哈希算法也可能得出相同的索引。
而用文件名和访问的文件比较,发现名字不对产生哈希冲突。
这时需要添加一个新的参数重新运算,如果仍不对,则可能目录不存在。
目录的本质是一个数据结构、FCB的集合、有结构的文件。
文件的分配方式
连续分配方式
把磁盘分为多个盘块,每个盘块固定大小为4K,与内存文件块号相对应。
例如:把某个文件分到磁盘上,右边表格则记录了它的信息。
文件名,所占起始块号,所占块号数量。
连续分配支持顺序和直接访问,速度快:
因为分配的盘块是连续的所以是顺序访问,当然可以通过计算地址,直接访问某个块号。
不方便扩展:
当文件内存想要读入新的内容时,若其所占盘块后的其他盘块不是空闲的,那么便不能直接扩展。
会产生磁盘碎片:
当内存文件分到对应的盘块上,但是用不完所有的盘块空间,那么便会产生内部碎片。
而需要扩展的文件要申请新的盘块,则原来的盘块可能会闲置,产生外部碎片。
链接分配方式
隐式链接分配
并没有说明文件中某个块号在磁盘中所占的所有盘块,只是通过链接的方式,让磁盘中的盘块依次链接。
支持顺序访问:例如图中可以从 1到10再到7 进行访问
方便拓展:想要添加盘块只需要令最后一个盘块再指向下一个空闲盘块即可
没有外部碎片
不支持直接访问:隐式链接不确定是哪个盘块因此不能计算地址以此来直接访问。
每个盘块的指向需要额外创建一个指针,所以需要占一定的空间。
而且隐式链接如果某个盘块丢失的话则会造成后续盘块都会丢失。
显式链接分配
显示链接把每个盘块的指针拿出来(防止指针丢失),然后放到一个文件分配表中。
磁盘有多少盘块,文件分配表就有多少条目。
文件分配表中 -2代表该盘块空闲 -1代表此后没有盘块。
当创建一个新文件时,只需将该新文件放到文件表中即可,其中起始块号填为no。
进行新文件分配时,要从文件分配表中读取下一块号为-2的物理块,作为起始块号和下一个块号。
这个文件分配表可直接放内存中,拿空间换时间。
索引分配方式
在显式链接分配中,如果磁盘中的盘块并没有被分配但它仍然要占用内存空间。此刻便有了更好的分配方式。
内存文件用磁盘中的盘块存放索引表中的磁盘盘块。 (这里的索引表就如同 显式链接中的文件分配表)
4K除以4B等于1024(4K指磁盘盘块大小,4B是物理块号所占位数)
而1024乘以4K等于4M(1024是盘块最多条目,4K是盘块大小)
一个文件表的最大内存空间为4M
此时需要更大的空间,那么便可以进行多级索引
二级索引表最大内存:1024乘以4M等于4G
混合索引
但是还有别的方式,就是把热点数据地址(局部性原理经常访问的数据)放到一级索引表的块号中,后面再放二级索引表。
类似于慢表和快表,快表中存放经常访问的数据(热点数据),这里可以把热点数据的物理地址放到一级索引表的块号中。
文件存储空间管理
空闲表法
将磁盘中连续的空闲盘块看作一个整体,然后记录第一个空闲块号,放到空闲盘块表中。
空闲链表法
空闲盘块链
将空闲的盘块组成一条链接。
空闲区块链
将空闲盘块表的条目组成一条链接。
空闲表法和空闲链表法的缺点就是
如果空闲的盘块太多那么会造成内存空间占用过多,并且分配空闲盘块也不方便。
成组链接法
把空闲盘块按数量分为几个组,例如:按100个盘块分组,每个分组的第一个盘块存下一组的信息,可存放下一组的盘块数量和盘块信息。
倒数第二组的第一个盘块是0/-1,表示后续无分组。
超级块
首先存放第一组的盘块信息,系统启动时自动载入内存。
超级块里面有一个空闲盘号栈,里面存放下一组空闲数和与下一组空闲数对应的下一组空闲块号。
第一个分组分完后,根据分组链接,接着分下一个。
如果栈满后就再生成一个数据结构栈,诸如此类。
位示图法
建立一个二维数组,每一个块号都有对应的位置。
如果块号空闲则为0,否则为1.
分配过程:
1.顺序扫描位示图,找到符合需要的0;
2.将找到的二进制位转成盘号b:b= n * i + j (n为该行有多少盘号)
3.修改位示图,令map【i,j】=1;(表示已经占用)
回收过程:
1.将盘块号转成行号和列号:i=b/n ; j =b%n
2.修改位示图,令map[i,j]=0(表示空闲)
输入输出设备管理
I/O设备的概念和分类
什么是I/O?
I/O就是“输入/输出”,将数据输入到计算机,或者接收计算机的数据输出到外部设备。
I/O设备分类
按照使用特性:
1.人机交互类外部设备;2.存储设备;3.网络通信设备
按照传输速率:
1.低速设备;2.中速设备;3.高速设备;
按照信息交换单位:
1.块设备;2.字符设备
块设备有明确的结构,字符设备没有明确的结构
I/O设备的构成
机械部件:比如键盘鼠标的按键和按钮,用来执行具体的I/O操作
电子部件:即I/O控制器、设备控制器,是CPU与硬件之间的桥梁
CPU通过控制设备控制器来操作机械部件
I/O控制器主要作用?
1.接收并识别CPU命令
2.向CPU报告设备状态
3.数据交换
4.地址识别
I/O控制器的组成
整体过程为CPU向I/O逻辑通信,发送命令或者传递地址译码,然后I/O逻辑与设备进行通信发送控制信息,获取设备信息然后返回到寄存器中,最后到达CPU.
地址线接收CPU的地址译码,控制线接收CPU的命令。
每一个设备对应一个寄存器。
例如:设备一对应数据寄存器一、控制寄存器一、状态寄存器一
设备二对应数据寄存器二、控制寄存器二、状态寄存器二
1.CPU与控制器间的接口
即CPU和控制器实现通信
2.I/O逻辑
I/O逻辑是整个I/O控制器的核心,一个I/O逻辑对应多个设备
3.控制器与设备间的接口
即控制器和设备实现通信
内存映像I/O,相当于把寄存器和CPU看作一个东西。
I/O的控制方式
程序直接控制方式(CPU直接控制)
CPU频繁干预;每次读/写一个字;读的过程:设备->CPU->内存
首先CPU通过地址线和控制线给IO逻辑发布命令,然后IO逻辑给状态寄存器发布一个“忙”的状态,
然后和设备进行通信,最后传回数据到数据寄存器,IO逻辑再给状态寄存器发布一个“空闲”状态。
最后CPU才读数据。
这里的“忙”类似于“忙等”状态,称为“轮询”,也是CPU频繁干预的解释。
CPU发布命令后会一直访问状态寄存器,直到完成命令。
数据从CPU到内存:CPU有一块高速缓存,可以存放数据。
中断驱动方式
第二步:CPU将此IO进程阻塞。
IO前后CPU干预;每次读/写一个字;读:设备->CPU->内存
CPU发出命令后,当前IO控制器发出中断指令,然后CPU将其阻塞。
IO控制器随后读/写数据,然后发送到数据寄存器,更新状态寄存器,状态寄存器变为“空闲”状态。
此时I/O控制器再发出一个指令请求唤醒,CPU检查状态寄存器是否为“空闲”。
然后CPU最后读取数据。
CPU不再轮询状态寄存器,且CPU和I/O控制器并行运行,但读/写的字就一个导致多次中断会浪费时间。
DMA方式
直接从内存到数据寄存器交换,不再经过CPU.
传输的单位是“块”;块之间传输需要CPU干预;设备<->内存
流程:
CPU启动I/O控制器,然后I/O控制器发送一个中断指令,CPU将其阻塞 。
随后,将状态寄存器(CR)置为“忙”,控制器与设备通信交互,获取数据放到DR(数据寄存器中),DC(数据计数器)进行加法操作。
一旦DC满足一个连续块的数据量那么就立即发送指令,请求唤醒。CPU检查CR后,将DR中的数据存入内存中。
DMA方式操作的是一个块的数据量,提高了效率;CPU和IO控制器可并行运行;每个IO指令操作一个块,如果遇到离散块需要频繁中断。
一个读指令只能读一个或多个连续的块,如果读取的文件有 1 2 3三个连续的块,那么读完第三块后,才会进行中断机构的操作。
若读完3号块要读6号块则需要再发布一个读指令,因此离散块需要频繁中断。
通道控制方式
通道是专门负责I/O的处理机。每次读/写一组数据块;I/O设备<->内存
过程:
CPU发出一个I/O指令给通道,(因为通道是一个专有的设备所以它也有个专有的指令),
然后拿到通道程序,与I/O设备进行通信交互,将数据直接写道内存里面。
接下来产生中断信号。
I/O通道既是个处理机也是个I/O控制器。
CPU和I/O控制器可以并行,不过硬件要求较高。
I/O软件层次
用户层软件
实现用户交互接口 ; 通过库函数实现系统调用
设备独立性软件
比较大的管理者,向下进行管理,向上提供接口。
向上一层提供调用接口;设备保护;容错处理;设备分配与回收;
数据缓冲区管理;逻辑设备与物理设备映射。
设备驱动程序
不同设备硬件特性不同,但CPU指令相同;
负责控制硬件设备,将CPu指令转成设备操作
驱动程序会以独立进程的形式存在
中断处理程序
I/O完成后发出中断信号;执行中断处理程序;会直接操作硬件
硬件
I/O核心子系统
I/O调度
各种调度算法
设备保护
假脱机技术(SPOOLing技术)
I/O操作与CPU操作比,IO操作是相当低效的。
输入/输出井:临时存放输入或输出数据的一块地址
输入/输出进程:通过 输入设备/输出设备进行输入/输出
输入/输出缓冲区:暂存输出/输入数据
输入过程:
一个字一个字的输入存到输入缓冲区,待存满一个块后,对输入井一次性输入。
输出过程:
输出井一次性输出到输出缓冲区,然后再一个字一个字输出到输出设备。
好处:
模拟脱机;提高效率;将独占的打印机变为共享的。
将独占的打印机变为共享的:
例如有多个作业进程想要输出,它们都会被放到输出井,然后进程依次排队由输出井输出到输出设备,实现设备的虚拟化。
设备分配与回收
设备分配应考虑的因素
有固有属性、分配算法、安全性,主要考虑共享、并发的问题。
静态分配和动态分配
设备管理中的数据结构
设备分配步骤
如果一个进程想要申请某个设备,
首先需要根据逻辑设备名查系统设备表(SDT),
其次查设备控制表(DCT),查询设备状态,如果设备空闲则分配给进程,如果设备忙碌就放到设备队列中等待。
然后查控制器控制表(COCT),查询控制器状态,如果空闲则分配,忙碌则放到控制器队列。
最后查通道控制表(CHCT),查询通道状态,空闲即分配,忙碌即放到通道队列。
------------------
如果设备回收也是逆操作罢了。
缓冲区管理
为了缓解CPU和I/O设备间 速度不匹配的矛盾而临时建立的临时存储区域
1.缓和CPU和I/O的速度不匹配的矛盾
2.减少CPU中断的频率,放宽对CPU响应时间的限制
3.解决数据粒度不匹配的问题
4.提高CPU与I/O设备的并行性能=
单缓冲
缓冲区大小和块大小一样。
非空不写
如果缓冲区里面不是空的,那么块设备不会输入数据到缓冲区。
非满不读
如果缓冲区里面不是满的,那么传送这个操作不会执行。
输入过程和处理过程是可以并行的,而传送不行;输入数据时可能在处理前一个的数据因此可以并行。
单缓冲:(工作区满,缓冲区空)处理一块数据耗时:Max(T,C)+ M
双缓冲
输入(T)和传送(M1)、传送(M2)、处理(C)是并行的
循环缓冲
用in指针向指定的缓冲区输入数据,用out指针向指定的缓冲区输出数据。
缓冲池
空缓冲队列、输入缓冲队列、输出缓存队列。
如果想要输出:
那么就从输出缓冲队列里面,访问队头,并且放到提取输出位置。
然后把输出完的 输出缓冲队列 放到 空缓冲队列 里面,
再找一个空缓冲队列放到收容输出位置来存放输出的信息。
如果想要输入:
那么就从 输入缓冲队列里面,访问队头,放到提取输入的位置。
然后把输入完的 输入缓冲队列 放到 空缓冲队列里面,
再找一个 空缓冲队列放到收容输入的位置存放输入的数据。