参考教材:《Operating System Concepts. 9th edition》(中文版 → 《操作系统概念 原书第9版》)
推荐用 电脑端 浏览
操作系统笔记 - 飞书云文档
第1章 导论
操作系统定义
- 操作系统:在计算机用户与计算机硬件之间运行的一个程序(软件)
- 工作内容:资源管理服务(包括硬件资源和软件资源)、资源管理服务、为用户提供服务(交互、提供应用程序的运行环境等)
计算机系统结构与组织
- 3.1 启动:Power On通电 -> 给主板motherboard供电 -> 执行BIOS程序 -> Bootstrap引导程序
BIOS:Basic Input Output System,确认每个设备是否工作正常,一般位于主板的ROM中,运行过程中会启动引导程序↓
Bootstrap:引导程序,用于初始化全部设备、将操作系统载入内存中,运行第一个及昵称init(),等待事件发生 - 3.2 中断:
一个事件的触发是通过 硬件中断 或 软件中断 来实现的。系统一旦发生中断,CPU会运行中断服务程序(Interrupt Service Routine),且每个中断都有自己对应的中断服务程序 ISR。系统通过中断向量表(Interrupt Vector Table)来管理中断请求与中断服务程序之间的对应关系。
软中断:即通过软件触发中断。系统调用(System Call)会触发软件中断。 如异常,除零,不可以屏蔽
硬中断:即硬件通过向 CPU发送信号来触发中断,一般对用户不可见,但可触发程序的运行。如网卡接收数据包,可以屏蔽
中断向量表:包括中断号和中断服务程序的地址(the addresses of all the service routines)
中断举例:I/O设备发生的事件(按键盘、点击鼠标、磁盘读写等)、异常事件/重要事件的发生(断电、部件失灵等)、非法指令(除零,下达不存在的指令等)
中断的工作流程(重要):保存当前进程的程序计数器(Program Counter)→ 跳到相应的中断服务程序中,运行相应的中断服务程序 → (中断程序运行结束)返回到被中断的程序(by PC),并继续往下运行 或 返回到操作系统指定的程序中
现代的操作系统一般被视为以中断驱动 (InterruptDriven )或事件驱动( Event-Driven )的系统 - 3.3 I/O结构:
I/O设备与CPU可同时运行
每个设备控制器负责相应类型的设备
每个设备控制器拥有自己的本地缓冲器和寄存器
工作流程:
CPU负责内存与本地缓冲器之间的数据传递
设备控制器负责在其所控制的外部设备与本地缓冲存储之间进行数据传递
I/O操作结束后,设备控制器通过中断通知CPU,表示I/O结束
传输单位为字节(byte),CPU和磁盘控制器小容量的寄存器用于传输数据
会出现的问题:CPU忙于接收设备控制器向它发送的中断通知
解决方案:DMA(直接访问内存)技术
① DMA控制器在没有CPU干涉的情况下,以块(Block)为单位,负责在设备缓冲器与主存之间的数据传送
② 之前是每个字节传送完成后就触发中断表示完成,而DMA是每完成块儿传送后触发中断
③ 有利于高速 I/O设备传送数据,接近于内存速度
DMA示例:读操作
① 程序化I/O通过提供所需的信息并启动传输,为磁盘控制器的传输做好准备
② DMA从磁盘到内存传输数据
③ 传输完成后,磁盘控制器向CPU发送完成中断
P47 4.2 每个CPU核心都有自己的寄存器和缓存是为什么?
答:便于每一个CPU核心可以独立进行运算
P84 7. 什么时候不接入互联网,但是互相之间能聊天?
答:局域网
第一次实验
./
表示当前目录
直接使用 ls 命令 没加./
但是仍然显示当前目录,是因为未指定目录的情况下,ls命令会从环境变量中找。
gcc -c helloworld.c 生成 helloworld.o文件,是目标文件,其文件格式为 ELF (executable and linkable format - 可执行可链接文件格式)
第3章 进程
进程的概念
一个进程载入内存之后,其表现形式有 数据段、代码段、堆、栈。
程序是被动的实体,如存储在磁盘上的包含一系列指令的文件内容,进程是活动的实体。
进程之间是树形结构
进程在运行时的状态:新的、运行、等待、就绪、终止
进程调度
进程调度队列
- 多道程序 multiprogramming:为了使 CPU利用率达到最大
操作系统持有就绪队列和一组设备队列,进程可以在多个调度队列之间移动
1. 就绪队列:
驻留在内存中的就绪并等待运行的进程(如进程创建时,被放到该队列), 即等待分配CPU的进程,一般用链表来实现
2. 设备队列:
等待特定I/O设备的进程队列
调度程序
- 长期调度程序 (作业调度程序) :
从存储设备的缓冲池中选择进程,并装入就绪队列中等待执行(I/O调度) - 中期调度程序(分时系统)
中期调度程序的核心思想是能将进程从内存中移出(从CPU竞争中移出),从而降低多道程序设计的程度(Swap In and Swap Out) - 短期调度程序(CPU调度程序)
从准备执行队列中选择一个进程,并为之分配CPU(CPU调度)
上下文切换
定义:将CPU切换到另一个进程,需要保存当前进程的状态,并恢复另一个进程状态
上下文切换时间是额外的开销,因为上下文切换时系统不能做什么有用的工作
进程的操作
进程创建
操作系统是根据一个 唯一的进程标识符(PID) 来识别系统中的进程。
- 进程创建步骤:
① 在系统内部创建进程控制块
② 分配内存
③ 载入可执行文件(通过调用exec()系统调用)
④ 初始化程序
进程终止
- 进程完成最后语句,并使用
exit()
系统调用请求操作系统删除自身,并终止运行,这时进程可以同通过wait()
函数 返回状态值 给父进程并释放资源,交由操作系统回收 - 父进程可以通过
abort()
系统调用终止子进程的执行
可能原因:1)子进程使用了超过它所分配的资源;2)分配给子进程的任务不再需要;3)父进程终止导致的子进程终止(级联终止) - 僵尸进程(zombie process),
是一个进程结束,但是他的父进程没有等待他(调用wait/waitpid),那么他将成为一个僵尸进程(带有 defunc 的标志)
进程间通信 IPC
系统内并发运行的进程可以是相互独立或协作工作,进程协作的理由有信息共享、提高运算速度、模块化、方便
- 进程间通信模型:
① 消息传递
适合传递较少数量的数据
需要内核的干涉
易于实现
② 共享内存
允许以最快的速度进行方便的通信
不需要内核的干涉
比消息传递速度快
共享内存系统
对于一般的系统环境:
每个进程都有自己受保护的内存地址空间
通常操作系统试图阻止一个进程访问另一个进程的内存地址空间
为了实现共享内存、便于两个或多个进程可以访问内存,共享区域应取消互访限制;而且,必须保障不能有两个以上的进程同时向共享区域写入数据,即需要一个同步机制
生产者和消费者问题:
缓冲区为 有限缓冲:如果缓冲为空,消费者必须等待;如果缓冲为满,则生产者不能产生新的信息
消息传递
通信线路的逻辑实现方法:
1)直接 / 间接通信
2)同步 / 异步通信
3)自动 / 显示缓冲(通信缓冲)
- 直接通信
需要通信的每个进程 必须明确命名通信的接收者和发送者
a. 对称寻址(一对一)
一个线路只与两个进程有关,两个进程之间只有一个线路
b. 非对称寻址(多对一)
接收者不需要命名发送者 - 间接通信
通过端口或邮箱来发送/接收消息,进程间通过共享端口来进行通信
两个通信进程间可能有多个线路,每个线路对应一个端口 - 同步通信
发送者:发送进程阻塞,直到消息被对方进程接收
接收者:接收者阻塞,直到有消息可用 - 异步通信
发送者:发送进程发送消息并继续操作
接收者:收到一个有效消息 或 空消息 - 缓冲
通信进程所交换的消息都驻留在临时的队列中,即缓冲区里
客户机与服务器系统间通信
- 套接字:IP地址 + 端口号
连接由一对套接字组成
TCP Socket为面向连接套接字,UDP Socket为无连接套接字 - 远程过程调用 RPC
每个独立的远程过程都有一个存根,隐藏了通信发生的细节
客户机调用位于远程主机上的过程时,
a. 客户端存根编组参数,并向服务器相应存根发送参数
b. 服务器存根接收参数,解组参数,并调用相应过程 - 远程方法调用 RMI
RPC调用远程子程序或函数,RMI调用远程对象的方法
RPC参数传递方式是普通数据结构,RMI参数传递方式可以是对象
管道 PIPE
管道通信方式的中间介质是文件(管道文件)
如两个进程利用管道文件进行通信时,一个进程为写进程,另一个进程为读进程
提供进程同步运行
分为:匿名管道 和 命名管道
- 匿名管道
双方通信时需要建立两个管道
只能用于父子进程或兄弟进程之间 - 命名管道
可在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信
管道的实现:FIFO
FIFO缓冲区类似队列,一个管道可以有多个输入,但是没有顺序保证
管道、消息队列、共享内存、套接字 优缺点对比
-
管道
具有亲缘关系的进程间的 匿名管道 通信方向固定(互相通信需要两个管道)
命名管道方向不固定
每个数据块由最大长度限制
命名管道存在同步和阻塞问题 -
消息队列
优点:
a. 我们可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。
b. 我们可以用一些方法来提前查看紧急消息。
缺点:
a. 与管道一样,每个数据块有最大长度限制
b. 系统中所有队列所包含的全部数据块的总长度也有上限 -
共享内存
不需要内核的干涉
速度最快
必须提供同步机制(因为内核不负责同步共享内存中的信息)
Linux无法严格保证提供对共享内存块的独占访问
第4章 线程
创建进程是重量级的操作过程, 而且进程之间的上下文切换也是一个代价比较高的操作
相对创建进程,创建线程比较简单,只需要复制栈和寄存器的内容
线程是运行在应用进程里的,比进程更小的运行单位,每个线程是独立的调度对象
一个进程可以拥有多个线程,线程之间共享以下内容
1. 代码段,全局变量
2. 打开的文件标识符
3. 工作环境,包括当前目录,用户权限等
多线程编程优点:
1. 响应速度快:即使部分线程发生阻塞,其他线程可以继续运行
2. 资源共享:共享所属进程的内存和资源
3. 经济:创建和切换线程更经济
4. 多处理器体系结构的利用:多线程可以在多处理器上并行运行
多线程模型
用户线程
用户线程是由用户层的线程库来管理,受内核的支持,但无需内核管理
内核线程
内核线程是由内核来管理,由内核来进行维护和调度
假设:操作系统支持内核线程;把内核线程看成是一个进程;用户线程基于内核线程运行,即用户线程阻塞内核阻塞、内核线程阻塞用户线程也阻塞
-
一对一模型
一个用户线程映射到一个内核线程的模型,Linux,Windows
优点:
1. 可以提供并发功能, 可以在多个处理器上并行执行
2. 在一个线程执行阻塞系统调用时,可以调度另一个线程继续执行 -
多对一模型
多个用户线程映射一个内核线程
线程由用户空间管理 -
多对多模型
多个用户线程映射多个内核线程 -
二级模型
多对多模型 + 允许用户线程绑定一个特定的内核线程 -
各个模型的缺点
一对一:创建一个用户线程就需要创建一个内核线程,造成内核负担重
多对一:一个用户线程一但被阻塞,其他用户线程也会阻塞(针对同一个内核线程服务的用户线程无法提供并发功能)
多对多:当一个线程执行阻塞系统调用时,内核能调度另一个线程的执行,但需要提供调度机制
线程库 略
多线程程序相关问题
系统调用 fork() 和 exec() 语义
- 如果进程中的某一个线程调用 fork(),那么新进程会复制所有线程呢,还是只复制调用 fork()的线程呢?
答:有的 Unix 系统提供两种形式的fork()系统调用,开发者可以决定只复制一个或者复制全部 - 那么,什么时候复制全部,什么时候复制一个好呢?
答:这取决于创建新进程的目的。如果调用exec(),就复制一个;如果不调用exec(),就复制全部
线程取消
- 异步取消(Asynchronous Cancellation):一个线程立即终止目标线程
- 延迟取消(Deferred Cancellation):目标线程不断地检查它是否应终止
信号处理
信号是用来通知进程某个特定事件的发生,这需要操作系统提供一种内核和进程之间的通信机制。信号有以下两种:
I. 同步信号(内部信号):进程本身事件产生的信号,如访问非法内存、除零等
II. 异步信号(外部信号):进程之外事件产生的信号,如按CTRL+C键等
信号处理程序由 默认~ 和 用户定义的 ~
线程池
在进程开始时创建一定数量的线程,并放入到进程池中等待工作
优点:
a. 用现有线程处理请求要比等待创建新的线程要快
b. 线程池限制了在任何时候可用线程的数量,这可以防止大量创建并发线程,有助于管理
调度程序的激活
多对多模型和二层模型中的用户线程和内核线程需要通信,以便维持内核线程的适当数量
调度程序激活:一种解决用户线程库和内核间通信的方法,提供UPCALL通信机制
第5章 CPU调度
- 多道程序的目的是使CPU的使用率最大化
- 一个进程的执行由 CPU执行(CPU区间) 和 I/O等待(I/O区间) 组成。进程在执行的过程中,不断在这
两个状态之间的进行切换
- I/O为主的程序里短CPU区间较多,CPU为主的程序里长CPU区间较少
- 每当CPU空闲时,调度程序(短期调度程序)从就绪队列中选择一个进程,并为之分配CPU
CPU调度准则
调度算法
先到先服务 FCFS
最短作业优先调度
选择进程的下一个CPU区间(剩余CPU区间)长度最短的进程,分为非抢占和抢占
对于给定的一组进程,在平均等待时间上,最短作业优先调度算法最优
优先级调度
每个进程都有它的优先级,通常用数字来表示进程的优先级,数字值越小它的优先级越高。分为非抢占式优先级调度,抢占式优先级调度
最短作业优先调度算法是优先级调度算法,一个进程的优先级与它的下一个CPU区间的长度成反比
可能会发生 低优先级进程无法运行的问题(饥饿 / 无限阻塞),例子↓
轮转法调度 RR
FCFS调度算法的变种,给每个进程分配一个时间片
系统每隔一个时间片发出一个时钟中断,并调度另一个进程执行
1. 每个进程只能运行给定的时间片并释放CPU,并被放入到就绪队列(RR调度是抢占调度)
2. 如果进程在给定的时间片内提前结束,发生中断并调度另一个进程
RR调度存在的问题:如果时间片太大会导致轮转法调度与FCFS(FIFO)相同,太小会导致上下文切换负载太重,如何确定时间片的长度?
答:如果绝大多数进程能在一个时间片内完成,那么平均周转时间会改善;根据经验,时间片应大于80%的CPU区间
多级队列调度 MLQ
将就绪队列分成多个独立的队列,每个队列内有自己的调度算法,并提供队列之间调度机制
若分为前台队列和后台队列,对于队列间调度机制,则:
① 固定优先级抢占调度
• 如前台队列比后台队列具有高优先级,但有可能产生饥饿问题
② 队列之间划分时间片
• 每个队列都有给定的CPU时间, 这个时间可用于调度队列内的进程
• 例如赋予前台队列80%CPU时间,赋予后台队列20%CPU时间
多级反馈队列调度 MLQF
多级队列,每个队列都有自己的调度机制;
进程在多个队列之间有移动(老化(aging)可以采用这种方式实现)
多处理器调度
-
Homogeneous (同构处理器):处理器功能、结构相同
-
Heterogeneous(异构处理器):处理器功能、结构不同
-
对称多处理(Symmetric):又称SMP,每个处理器有自己的调度算法 ,不允许处理器之间的移动
-
非对称多处理 (Asymmetric) :只有一个处理器进行调度任务,允许处理器之间的移动
-
进程移动时,CPU的缓存之间需要实时同步缓存数据,所以尽量把进程放入到同一个处理器上运行
1. 软亲和性:允许处理器之间的移动
2. 硬亲和性:不允许处理器之间的移动 -
负载平衡
在SMP系统中,保持所有处理器的工作负载平衡
负载平衡是设法将工作负载平均地分配到SMP系统中的所有处理器上
负载平衡通常有两种方式,并相互不能排斥
- Push(推) migration
- Pull(拉) migration
线程调度
区分用户线程和内核线程, 多线程系统的调度对象是线程
- local 调度 (多对一和多对多模型)
线程库调度用户级线程到一个有效的 LWP,也就是用户线程映射内核线程,被称为进程竞争范围PCS
– 根据优先级完成,一般是由程序员给定
– 竞争发生在相同进程的线程之间 - Global 调度(一对一模型)
系统将内核线程调度到有效的物理处理器上,被称为系统竞争范围SCS
– 竞争发生在系统的所有线程之间
实时调度
实时系统中的进程具有截止时间(deadline)要求,进程必须在给定的截止时间内完成执行,有截止时间的进程称为实时任务(real-time tasks)
- 硬实时系统:
» 具有硬截止时间,必须在截止时间内结束任务
» 例如,军用设备、医疗设备 等 - 软实时系统:
» 任务具有软截止时间,可以适当的超过截止时间结束任务
» 例如,音频、视频系统 等
- 紧急任务先处理算法
第6章 进程同步
如果没有进程间的同步保障机制会发生竞争条件(race condition)问题
避免发生竞争条件的关键问题是 确保操作共享数据的代码段的执行同步(互斥运行),不能让多个进程同时运行操作共享数据的代码段
临界区问题
多个进程同时操作共享数据时,每个进程拥有操作共享数据的代码段(程序段),该代码段即为 临界区
解决竞争条件问题的关键是:1)确保单个进程在临界区内执行;2)确保其他进程也可以进入临界区;
解决临界区问题需要满足的条件:
1. 互斥:某⼀个进程进⼊了临界区,其他进程就不能进⼊
2. 前进:如果没有进程在临界区执⾏,则必须确保⼀个进程进⼊临界区
3. 有限等待:⼀个进程从请求进⼊临界区,直到该请求被允许,必须有限等待
信号量
无忙等待的同步工具,适用于单个或多个资源的同步操作
二进制信号量(互斥锁)
适用于单资源的共享,mutex为资源数量,初始化为1;信号量的值只能为0 或 1
计数信号量
适用于多资源共享,共享资源的数量为n
wait( n)操作为减,signal( n )操作为加,当n为o时表明所有资源都被占用
题目:假设要求P1的语句s1完成之后,执行P2的语句S2,共享信号量synch,并初始化为0,伪代码如下
P1:
S1;
signal(synch);
P2:
wait(synch);
S2;
第7章 死锁(deadlock)
分析死锁问题
- 死锁发生的 4 个必要条件:
互斥:⼀个资源只能由⼀个进程占⽤
占用并等待:⼀个进程必须占⽤⼀个资源,并请求/等待另⼀个资源
非抢占:资源不能被抢占
循环等待:有⼀组等待进程 {P0, P1, …, Pn},P0 等待的资源被 P1所占⽤,P1 等待的资源被 P2 所占⽤,…, Pn–1 等待的资源被 Pn 所占⽤,Pn等待的资源被P0 所占⽤
资源分配图:资源分配图由节点集合 V 和⼀个边集合 E 组成
分配图与死锁:① 如果分配图没有环,就没有死锁;② 如果分配图有环,就有可能发⽣死锁
(对于②情况,如果每个资源类型只有⼀个实例,就肯定会发⽣死锁;如果每个资源类型有多个实例,就有可能处于死锁)
死锁处理方法:
1. 预防死锁:确保至少一个必要条件不成立
2. 避免死锁:利⽤事先得到进程申请资源和使⽤资源的额外信息,判断每当发⽣资源请求时是否会发⽣死锁
3. 发生死锁,检查并恢复:确定死锁是否确实发生,并提供算法从死锁中恢复
4. 忽略死锁问题
预防死锁
- 针对必要条件预防死锁:
① 互斥:不能通过否定互斥来预防死锁
- 不可共享资源必须确保互斥,如 打印机
- 可共享资源不要求互斥访问,如 只读文件
② 占有并等待:确保⼀个进程请求⼀个资源时,它没占有其他资源
- 每个进程在执行前申请并获得所有资源
- 进程只有在不占用资源时,允许进程申请资源
缺点:①和②会导致资源利用率低和可能发生饥饿问题
③ 非抢占:如果一个进程占有资源,并且申请另一个不能被分配的资源,那么其现已分配的资源可被抢占
如果⼀个进程申请⼀些资源,那么⾸先检查它们是否可⽤:
- 如果可用,就 分配
- 如果不可用,检查这些资源是否已分配给其他等待额外资源的进程,如果是,那么就抢占
- 如果不可用,且也没有被其他等待额外资源的进程占有,那么就等待
④ 循环等待:为每个资源类型分配一个唯一的整数,每个进程按递增顺序申请资源
避免死锁算法
资源分配图算法:适⽤于每个资源具有单个实例时
引入需求边Pi——>Rj:表示进程Pi可能将来会申请资源Rj
银行家算法:(资源请求算法 + 安全性算法)
Available
(vector向量):表示送hi可分配的资源数;
- Available[i] = k 表示资源Ri的可用资源数是k个
Max
(n*m矩阵):表示资源最大需求数;- Max[i,j] = k表示进程Pi可能请求的资源Rj的实例个数是k
Allocation
(n*m矩阵):表示占有的资源数;
- Allocation[i,j] = k 表示进程Pi可已经占有的资源Rj的实例个数是 k
Need
(n*m矩阵):表示为了完成任务可能仍然需要的资源数;
- Need[i,j] = k 表示进程Pi可能需要的资源Rj的实例个数是 k
每次进程请求资源时,运行资源请求算法,确认是否允许请求
Resource Request Algorithm:
if (Request i <= Need i) //检测资源的请求是否合法
if (Request i <= Available i) {
Available i = Available i - Request i;
Allocation i = Allocation i + Request i;
Need i = Need i - Request i;
do Safety Check Algorithm; //检查分配资源后是否安全
else
waiting;
end if
else
error message;
end if
Work
:表示可用的资源数量
Finish
:表示结束分配的进程
Safety Check Algorithm:
Work = Available;
for all i, Finish[i] = false;
for all i do
// 进程i还在等待分配资源 且 请求的资源不超过可用资源的数量
if (Finish[i] == false && Need i <= Work)
Work = Work + Allocation i; // 释放进程i占有的资源
Finish[i] = true; // 进程i在资源的使用上已经完成
end if
end for
if for all i, Finish[i] == true
Then the system is safe
end if
练习题:
通过运⾏安全性算法确定是否是安全状态,结果发现是安全状态,并【P1,P3,P4,P0,P2】为安全顺序。则允许P1的(1,0,2)的请求。
问:
• 是否能允许P4 的请求(3,3,0)?
• 是否能允许P0 的请求(0,2,0)?
答:
1. 不允许;P4_req = 330 < Avail(332),进入资源分配算法,Avail_new = 332-330=002,Alloc[4]_new = 002+330=332,Need[4]_new = 431-330=101,For all i, Avail_new < Need[i], So it is not safe. No allow.
2. 允许;P0_req = 020 < Avail(332), run resourse request algo…, Avail_new = 332-020=312, Alloc[0]_new = 010+020=030, Need[0]_new = 743-020=723, run safety check algo…, get the safe order [P1,P2,P3,P0,P4], so allow P0_req.
死锁检测
Available
(vector向量):表示送hi可分配的资源数;
Allocation
(n*m矩阵):表示占有的资源数;
request
(n*m矩阵):表示当前每个进程的资源请求情况;
检测算法:
detection algorithm:
// 初始化,设定状态
Work = Available;
for all i do,
if allocation[i] != 0, Finish[i] = false; // 检测死锁时,只考虑占有资源的进程
else Finish[i] = true;
end for
// 分配并收回资源
for all i do, // 类似银行家算法中的安全性算法
if Finish[i] == false && request[i] <= Work
Work = Work + Allocation[i];
Finish[i] = true;
end if
end for
// 检查死锁情况
if there is a i, Finish[i] == false
then the system is deadlock
end if
练习题:
答:1) init: Finish(0,1,2,3,4) is false.
2) both req[0] and req[2] = 000, so availble = P0_alloc+P2_alloc=010+303=313, safe order [P0, P2]…… finally, safe order is [P0, P2, P3, P4, P1] (注意不是 02134,2检查完应顺序下沿至3)
何时调⽤算法取决于:
- 死锁发⽣的频率
- 死锁发⽣时,有多少进程会受影响
用途:每次资源请求调⽤检测算法;每次资源请求不被允许时调⽤检测算法
死锁恢复
solution 1:终止进程
solution 2:资源抢占
第8章 内存管理
编译 与 链接
内存地址编址方式
1. 逻辑地址
– 也叫相对地址,⽤户程序在经过编译后形成的⽬标代码,其⾸地址⼀般为0,其余指令中的地址都是相对于⾸地址来编址。
– 不能⽤逻辑地址直接寻址
2. 物理地址
– 也叫做内存地址或绝对地址,把内存分成很多个⼤⼩相等的存储单元,每个单元给⼀个编号,这个编号称为物理地址
– 物理地址可以直接寻址
地址绑定是逻辑地址到物理地址的映射
动态加载、动态链接、静态链接
- 动态加载:直到被调⽤之前,程序不会被载⼊到内存,即加载延迟到运⾏时, 如 exec(“/bin/ls”) 系统调⽤
优点:
– 内存使⽤率高:不使⽤的程序不会载⼊到内存
– 适合⽤户⽤⼤量代码来操作不常发⽣事件
– 不需要操作系统的特别⽀持,由程序员来设计决定
示例指令:gcc libtest.c -shared -fPIC -o libtest.so
→ 生成 libtest.so 的动态库文件 - 静态链接:加载程序将库的内容合并到⼆进制程序镜像中,⼀直驻留在内存
- 动态链接:程序启动时建⽴了链接(即只有链接地址),需要时载⼊内存,由操作系统决定,通常适⽤于系统库, 如语⾔库
• 常规编译:gcc -o
main
main.o bill.o fred.o
• 静态链接:gcc -o
slmain
main.o libfoo.a
• 动态链接:gcc -o
dlmain
main.c -L ./ -ltest
交换
问:将交换出的进程再交换(调回)回来的时候,应调回到哪个内存空间?
应考虑以下三种情况决定:1)编译时绑定; 2)加载时绑定; 3)执⾏时绑定;
1、2)编译时/加载时绑定:必须回到原位,不可以移动到不同的地址(即 运行时不可以发生地址变化)
3)执行时绑定:可以移动到不同的地址(即运行时可以发生地址变化)
内存分配方式
分页
页表的实现:
1. 用一组专用寄存器来保存(成本太高)
2. 将页表放入内存中,需要页表基寄存器(页表基地址)和页表长寄存器(页表长度偏移量)
问:若把页表存入内存时,可能会出现的问题是?
答:根据进程的指令访问内存中的某一个数据时,会发生两次访问内存(效率低),第一次访问页表,从页表中寻找物理地址有关信息,第二次访问是真正访问数据。
解决方案:采用硬件缓冲(TLB:地址转换旁观缓冲),即在高速缓存区TLB中查找页表,有即用,没有则到内存的页表中查询(类似于缓存结构),还需要利用一些算法解决TLB中信息替换问题
分页优点:
① 有效的使用内存空间,对内存相对连续的分配方式
② 通过共享页表,实现了代码的共享
(可共享代码)每个进程共享代码段的页逻辑地址相同,(不可共享代码)针对私有代码和数据的也逻辑地址不同
页表的结构:
简单来说,就是页号和页偏移
在实现页表方式上,有 层次结构、哈希结构、反向页表结构
层次结构页表存储结构的优点
① 可以实现页表的不连续存储
② 可以节约内存空间
P71页思考题:64位三级页表结构
为什么是 32位.10位.10位,与10.32.10或10.10.32的区别是什么?(需要自己查资料,书上没有)
哈希页表
处理超过32位地址空间的常⽤⽅法
逻辑地址的定义为【虚拟页码(key),偏移量】
哈希页表的每⼀条⽬是链表,链表的每个元素包括【虚拟页码,所映射的帧号,下⼀个元素指针】
根据虚拟页码(哈希值)找到匹配的条⽬,并在链表⾥找到相对应的帧号,并⽤帧号和页偏移形成物理地址
反向页表
为了减少页表消耗的内存空间⽽采⽤的⽅法,即整个系统只有⼀个页表,页表对于每个真正的内存页或帧才建⽴⼀个条⽬
地址信息:需要⽤页码和页偏移来确定空间
进程信息:需要⽤进程标识符确定进程信息
反向页表编址:【进程标识符,页码,页偏移】
缺点:查找页表费时
分段
逻辑地址的定义:【分段号, 偏移】
需要段表,段表条⽬包括 { 段基地址,段界限 }
第9章 虚拟内存
虚拟内存的优点:
① 逻辑地址空间可大于物理地址空间
② 可以被多个进程共享地址空间
③ 可以提供更有效的进程创建
有效(v):页在物理内存中(可以被使用)
无效(i):页在虚拟内存中,不在物理内存中(需要先载入到物理内存才能使用)
- 当访问无效页时,系统报 页错误
- 页错误触发 从虚拟内存到物理内存的 载入
页置换
页置换是按需调页的基础,它分开了逻辑内存和物理内存,给程序员提供的巨大的内存空间
- 方法一:换出
每一页关联一个 修改位,确认关联页是否被修改
- 如果被修改过,在换出时必须写入磁盘
- 如果没有被修改过,则不需要写入磁盘,可以避免写入磁盘操作 - 方法二:换入(页缓冲)
利用空闲帧缓冲池(先入后出)
系统保留一个空闲帧缓冲池,当需要牺牲帧写出虚拟内存时,写出之前,从空闲帧缓冲池中先得到内存(即先分配后换出)
页置换算法
目标是:最小化页错误的发生
FIFO
最优置换
置换将来最长时间不会用的帧
但是 很难推测引用串的未来信息
LRU 最近最少使用
每个页关联该页上次使用的时间,选择最长时间没有使用的帧
采用栈实现方法需要每次更新栈,需要栈中项的移动
每当引用一个页,当该页移动到栈顶,并依次向下移动,最近不常用的帧在栈底
附加引用位算法
二次机会算法
增强型二次机会算法
基于计数的页置换
物理帧的分配
物理帧的分配方式:平均分配、比例分配、优先级分配
页置换可分为:全局置换、局部置换
全局置换:从所有帧集中选择一个置换帧(分配到的帧数量可能发生变化)
局部置换:仅从自己的分配帧中选择一个置换帧(分配到的帧数量不会发生变化)
第10章 文件系统接口
共享文件和目录的实现方法:
符号链接:创建一个 称为链接 的新目录条目。链接实际上是另一文件或目录的指针(类似快捷方式← 个人理解)
非符号链接:共享目录中重复所有被共享文件的信息,但必须提供一致性(同步机制)(类似直接拷贝到共享目录,还要确保两个目录下文件信息同步 ← 个人理解)
2020春考试题
一、填空题
-
操作系统是一直运行在计算机上的程序,它是(资源管理平台),(运行程序的平台),也是(为用户提供服务的平台)
-
多道程序系统(Multi-Programming system)的目的是(使CPU使用率最大化)
-
不可中断的指令一般称为(原子指令)
-
操作系统提供给编程人员的接口是(系统调用)
-
为了保护操作系统,操作系统一般提供双重运行模式,分别为(用户模式)和(内核模式)
-
操作系统通过(进程控制块(PCB))来管理和控制进程的相关信息
-
DMA直接访问内存是在专门的硬件控制下,实现(高速外设)和(主存储器)之间自动成批交换数据的技术
实际上是没CPU干涉情况下,在设备缓冲器和主存之间,以块block为单位的成批交换数据,每完成一块触发中断,比之前每直接中断一次要好
-
程序是(被动)的实体,而进程是(活动)的实体,它在系统中一般具有(新的),(运行),(等待),(就绪),(终止)5种状态
-
若某一个进程拥有100个线程,这些线程都属于用户级线程,则每一个线程在系统调度时间上占用的时间片是(1/100)。
解析:对于用户级线程而言系统是不知道的,当使用(ULT)用户级线程的时候,线程的创建,调度,切换是用户程序在用户态自己干的事,系统不知道,这种时候就是按进程为单位分配时间片,一个进程一轮就分配一个时间片(你内部怎么分是你自己的事);当是内核支持线程的时候,这个时候系统是知道(内核支持很多就知道)一个进程有多少个线程的,所以分配以线程为单位,这个进程有几个线程就给几个时间片
-
多线程进程中,因某一个线程的阻塞导致整个进程会被阻塞的关系模型是(多对一模型)
-
一个进程的运行一般由(CPU执行(CPU区间))和(I/O等待(I/O区间))组成
-
CPU 调度算法一般大分为(抢占式调度)和(非抢占式调度)
-
临界区是指进程中用于访问操作(共享数据)的那段代码段
-
发生死锁的四个必要条件是(互斥),(占用并等待),(非抢占),(循环等待)
-
文件访问控制信息存储的数据结构叫做(文件控制块(FCB)?)
二、简答题
1.传统的I/o操作会涉及到CPU、内存、I/o设备控制器、I/o设备本地缓冲区。请简述 I/o操作工作流程。
在开始I/O时,设备驱动程序加载设备控制器的适当寄存器。相应地,设备控制器检查这些寄存器内容,以便决定采取什么操作(如“从键盘中读取一个字符”)。控制器开始从设备向本地缓冲区传输数据。一旦完成数据传输,设备控制器就会通过中断通知设备驱动程序,它已完成了操作。然后,设备驱动程序返回控制到操作系统。对于读操作,数据或数据指针也会返回;而对于其他操作,设备驱动程序返回状态信息。
参考教材 P8
2.多处理器环境下为什么每个处理器都必须持有自己的寄存器和高速缓存。
便于每一个CPU核心可以独立进行运算
3.简单说明进程在内存中的表现形式,也就是一个进程在内存中结构。
一个进程载入内存之后,其表现形式有 数据段、代码段、堆、栈。
4.在多线程进程中线程之间可共享的和不可共享的都有哪些。
共享的资源有:堆、全局变量、静态变量、文件等公共资源(来自百度)
代码段,全局变量;打开的文件标识符;工作环境,包括当前目录,用户权限等(来自ppt)
a. 堆 由于堆是在进程空间中开辟出来的
b. 全局变量 它是与具体某一函数无关的,所以也与特定线程无关
c. 静态变量 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的
d. 文件等公用资源 这个是共享的,使用这些公共资源的线程必须同步。
不可共享的资源有:栈、寄存器
a. 栈 栈是独享的
b. 寄存器 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC
5.CPU 调度算法的调度准则有哪些。
CPU使用率、吞吐量、周转时间、等待时间、响应时间。
6.简单说明解决临界区问题需要满足的三个条件。
互斥、前进、有限等待
7.请比较说明 忙等待(busy-waiting) 与 阻塞唤醒(block-wakeup) 机制。
忙等待:指在单CPU情况下,一个进程进入临界区之后,其他进程因无法满足竞争条件而循环探测竞争条件(循环等待进入临界区的机会)
阻塞唤醒:就是将处于运行状态的忙等待进程,将其转换成等待(阻塞)状态,等到可以进入临界区时,再将进程从等待状态转换成就绪状态(第一次状态转换为blocking,第二次状态转换为wake-up)
至于哪个方法更优,取决于上下文切换(挂起和唤醒的负荷) 或 进入临界区的大小(运行代码量大小使用资源事件长短)
8.请简单说明静态链接,动态链接,动态加载,以及它们之间的区别。
静态链接:加载程序将库的内容合并到⼆进制程序镜像中,⼀直驻留在内存
动态链接:程序启动时建⽴了链接(即只有链接地址),需要时载⼊内存,由操作系统决定
动态加载:直到被调⽤之前,程序不会被载⼊到内存,即加载延迟到运⾏时,由程序员决定
9.请简单说明页表的三种实现方式。
层次结构、哈希结构、反向页表
10. 共享文件和目录的实现方法有两种分别为符号链接(symbolic link) 和非符号链接(hard link)。请简单说明它们的概念以及区别。
符号链接:创建一个称为链接的新目录条目。链接实际上是另一文件或目录的指针
非符号链接:共享目录中重复所有被共享文件的信息,但必须提供一致性(同步机制)
第十章 ppt31页
三、论述题
- 假设要求P1的语句s1完成之后,执行P2的语句S2,共享信号量synch,并初始化为0,请编写伪代码
P1:
S1;
signal(synch);
P2:
wait(synch);
S2;
四、应用题
进程调度
银行家算法
虚拟内存算法(fifo、lru等)(还没看!!!