文章目录
- 1 introduction
- 2 启动、中断、异常和系统调用
- 2.1 启动
- 2.2 中断、异常、系统调用
- 3 内存管理
- 3.1 连续内存分配
- 3.2 非连续内存分配
- 3.3 虚拟内存
- 3.4 页面置换算法
- 3.4.1 局部置换算法
- 3.4.2 全局置换算法:
- 3.4.2 抖动和负载控制:
- 4 进程控制
- 4.1 线程
- 4.2 进程控制
- 4.2.1 进程创建
- 4.2.2 进程切换
- 4.3 处理器调度
- 4.4 同步互斥
- 4.5 信号量和管程
- 4.5.1 生产者-消费者问题
- 4.5.2 哲学家就餐问题
- 4.5.3 读者-写者问题
- 4.6 死锁
- 4.7 进程通信
- 5 文件管理
- 5.1 文件缓存
- 5.2 文件分配:分配一个文件数据块的位置和顺序
- 5.3 空闲空间组织和冗余磁盘阵列
- 6 I/O管理
1 introduction
**教学内容:**操作系统结构、中断及系统调用、内存管理、进程线程,处理器调度、同步互斥、文件系统、I/O子系统
操作系统的定义:
- 一个控制程序
- 一个资源管理器
操作系统的组成:
- shell
- gui
- kernel
操作系统内核特征:
- 并发
- 共享:同时访问/互斥天
- 虚拟:多道程序设计
- 异步:走走停停
操作系统的演变:
单用户系统->批处理系统、多程序系统->分时系统->个人计算机、分布式计算机
操作系统结构:
简单系统:不同机器都操作系统不一样,可移植性差
分层结构:提高了可移植性:unix
微内核结构(microkernel):更灵活,但性能更差
现在的操作系统基本是微内核结构和分层结构的混合体
2 启动、中断、异常和系统调用
2.1 启动
BIOS:Basic Input Output System,是一组固化到ROM上的程序,是个人电脑启动时加载的第一个软件
BIOS启动固件作用:
- 基本输入输出程序
- 系统设置信息
- 开机后自检程序
- 系统自启动程序:将记载程序从磁盘都引导扇区(512字节)加载到0x7c00,之后跳转到0x7c00,将操作系统的代码和数据从硬盘加载到内存中,跳转到操作系统都起始地址
**系统启动出始化,从0xFFFF0读第一条指令,CS:IP=0xF000:FFF0,第一条指令啥跳转指令 - BIOS初始化
- 硬件自检
- 显卡等设备都初始化
- 执行系统BIOS
- 按制定启动顺序从软盘、硬盘或光驱启动
- 主引导记录MBR:有硬盘分区表描述分区状态和位置,加载并跳转到磁盘上都引导程序
- 跳到活动分区的引导分区,再跳转到加载程序
- 加载程序(bootloader)从文件系统中读取启动配置信息,根据配置去加载内核
UEFI:统一的可扩展固件接口(Unified Extensible Firmware Interface)再所有平台上一致都操作系统启动服务,对引导记录都可行性进行检查
2.2 中断、异常、系统调用
异常:非法指令导致当前指令失败后都处理请求
中断:来在硬件设备都处理请求
系统调用:应用程序主动向操作系统发出都服务请求
程序访问通常啥通过高层次API接口而不是直接进行系统调用
三种最常用都应用程序编程接口(API):
- win32 API for windows
- POSIX API for Unix, Linux, Mac OSX
- Java API for JVM
系统调用和函数调用都不同 - INT和IRET用于系统调用,涉及到堆栈切换和特权级都转换
- CALL和RET用于函数调用,不需要堆栈切换
- 因为内核态和用户态的切换,系统调用都开销是大于函数调用都
3 内存管理
内存管理的目标
抽象:逻辑地址空间
保护:独立地址空间
共享:访问相同内存
虚拟化:更大都地址空间
内存管理方式:
重定向relocation
分段segmentation
分页paging
虚拟存储virtual memory
3.1 连续内存分配
连续内存分配:给进程分配一块不小于指定大小都连续都物理内存区域
内存碎片:不能被利用都空闲内存,内部碎片和外部碎片
动态内存分配:当程序被加载执行时,分配一个进程指定大小可变分区:
动态分区的分配测略:
- 最先匹配:简单,会有外部碎片,分配大空间内存时速度慢
- 最佳匹配:避免大都空闲分区被拆分,但释放分区较复杂
- 最差匹配:中等大小都分配较多时,效果最好,避免出现太多小碎片,释放分区较复杂
碎片整理: - 紧凑:调整进程占用都分区位置来减少或避免分区碎片,需要保证所有应用程序啥可动态重定位
- 分区对换:抢占并回收处于等待状态进程都分区,以增大可用内存空间
伙伴系统buddy system:
初始状态只有一个大小为的空闲块,从小到大在空闲块数组中找最小的可用空闲块,如果空闲块过大,对空闲块进行二等分,直到大小合适都可用空闲块
空闲块合并条件:大小相同,地址相邻,起始地址较小都块都起始地址是
3.2 非连续内存分配
连续分配的缺点:物理内存必须连续,存在外碎片和内碎片,内存利用率低
非连续分配:允许共享代码和数据,支持动态加载和动态链接
段式存储管理segmentation:
将进程空间由多个段组成:数据、代码、堆栈,粒度比较大
段号去段表找基址,加上偏移就是物理地址
页式存储管理
将物理地址空间划分成相同大小的基本分配单元
帧frame:物理内存被划分成大小相等的帧
页page:逻辑地址空间被划分成大小相同的页
页表:逻辑地址到物理地址之间都映射关系
页表基址寄存器PTBR:page table basse register
如何减少页表大小?
- 快表TLB:translation look-aside buffer:缓存近期访问的页表项
- 多级页表:通过间接引用建立页表树
- 页寄存器:让页表与物理地址相对应,根据物理帧号寻找逻辑页号:逻辑地址进行hash变换->快表中找页表项
- 反置页表:类似页寄存器,把进程id也考虑进来:逻辑地址+pid进行hash变换->反置页表中找页表项
段页式存储管理需求
段式存储在内存保护方面有优势,页式存储再内存利用效率和优化转移到后备存储方法有优势
在段式存储管理都基础上,给每一个段加一级页表
逻辑地址->段表->页表->物理地址
段页式存储管理中都内存共享:不同进程的段表中的共享段,指向相同的页表项
3.3 虚拟内存
覆盖overlay:程序员给出模块间逻辑覆盖结构,发生再运行程序都内部模块间
交换swap:以进程为单位交换,发生在内存进程间
虚拟存储技术都目标:只把部分程序放到内存中,从而运行比物理内存大的程序
实现进程在内存和外存之间的交换,从而获得更多的空闲内存空间
分支局部性:一条跳转指令的两次执行,很可能跳到相同的内存位置
缺页异常->查找在外存中都页面->页面置换
3.4 页面置换算法
置换算法:当出现缺页异常时,调入新页面且内存已满时,置换算法选择被置换的物理页面
页面锁定:描述必须常驻内存的逻辑页面,是操作系统的关键部分,或者是要求相应速度的代码和数据
局部页面置换算法:置换页面的选择范围仅限于当前进程占用的物理页面内
全局页面置换算法:置换页面的选择范围是所有可换出的物理页面
3.4.1 局部置换算法
- 最优置换算法optimal:置换未来最长时间不访问的页面,是理想情况,实际系统中无法实现
- 先进先出算法FIFO:链表元素按驻留内存的时间排序,链首最长,链尾最短
- 最近最久未使用算法LRU:选择最长时间没有被引用的页面进行置换,是最优置换算法的一个近似
可以通过页面链表来实现,维护一个按最近访问时间排序的页面链表,或者是活动页面栈 - 时钟置换算法:在LRU和FIFO的折中,设一个访问位,访问页面的时候,访问位置1,缺页的时候指针顺序检查环形链表,就像时钟一样
- 改进的时钟置换算法:如果,一个页面有修改,则修改位为1,缺页时跳过有修改的页面,有修改的页面可以在其他时候写到外存中
- 最不常用算法LFU:每个页面设置一个访问计数,访问页面时访问计数加1,缺页时置换计数最小的页面
belady现象:采用FIFO算法,可能出现分配物理页面数增加时,缺页率反而增加
这是因为FIFO记录信息少,而LRU算法因为记录信息更多,没有belady现象,但是开销也更大
3.4.2 全局置换算法:
因为进程在不同阶段的内存需求是变化的,所有全局置换算法需要确定分配给进程的物理页面数
CPU利用率和并发进程数存在相互促进和制约的关系:
并发进程导致内存访问增加,并发进程的内存访问会降低访存的局部性特征
工作集指当前时刻t前的时间窗口中的所有访问页面所组成的集合
工作集置换算法:换出不在工作集中的页面,有点类似LRU
缺页率=缺页平均时间间隔的倒数
缺页率算法:如果进程缺页率过高,则增加常驻集以分配更多的物理页
3.4.2 抖动和负载控制:
**抖动thrashing:**进程物理页面太少,不能包含工作集,频繁置换
所以说操作系统要在并发和缺页率之间达到一个平衡,调节并发进程数MPL进行系统负载控制
最好是内存的大小
或者是平均缺页间隔时间(MTBF)=缺页异常处理时间(PFST)的点,这时候我们认为缺页的时候缺页异常来得及处理
4 进程控制
进程控制块PCB:porcess control block:操作系统管理控制进程运行所用的信息集合
- 进程标识信息
- 处理机现场保存:PC, SP
- 进程控制信息:进程间通信和存储信息
三状态进程模型:运行、就绪、等待,此外还有创建和退出这两个状态
进程挂起:处于挂起的进程映像放在外存中 - 就绪到就绪挂起:高优先级进程等待,低优先级进程就绪,为了释放空间
- 等待挂起:就绪进程需要更多的内存空间
- 运行到就绪挂起:在抢先式分时操作系统中,高优先级进程就绪
激活:把一个进程从外存转到内存
4.1 线程
单进程多线程系统:对并发执行要求高、对信息共享要求高,对安全隔离要求低
线程能减少并发执行的时间和空间开销:
线程的创建时间、终止时间、切换时间比进程短,共享内存和文件资源
用户线程:用一组用户级的线程库函数来完成线程的创建终止同步和调度,可以自己写调度算法,不需要和内核态切换,
缺点是线程发起系统调用而阻塞时,整个进程进入等待,线程只能按进程分配CPU时间,多个线程进程中,每个线程的时间片就少
内核线程:由内核维护PCB和TCB,使得进程是资源分配的单位,线程是处理器调度单位
**结论:**用户线程和内核线程一对一最好
4.2 进程控制
4.2.1 进程创建
windows进程创建api:CreateProcess(filename)
unix进程创建系统调用api:fork/exec
fork()父进程返回子进程pid,子进程返回0
exec()加载新程序取代当前运行进程pid不变
main{
int childPID=fork();
if(childPID==0)
<子进程执行代码>
else
<父进程执行代码>
}
4.2.2 进程切换
进程生命周期的信息:寄存器、CPU状态、内存地址空间
为了提高效率,采用汇编代码保存寄存器状态
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
pid_t pid;
int i;
for(i=0;i<3;i++){
pid=fork();
if(pid<0){
printf("fork failed");
exit(-1);
}
else if (pid==0){
printf("i=%d, pid=%d, parent pid=%d\n",i, getpid(), getppid());
}
wait(NULL);
/*exit(0);*/
}
}
wait()系统调用:
子进程结束时通过exit()向父进程返回一个值
父进程通过wait()接受病处理返回值
4.3 处理器调度
处理器调度:从就绪队列中挑选下一个占用CPU运行的进程
比较调度算法的准则:
- CPU使用率:CPU处于忙状态的时间百分比
- 吞吐量:单位时间内完成的进程数量
- 周转时间:进程从初始化到结束的总时间
- 等待时间:进程在就绪队列中的总时间
- 响应时间:从提交请求到产生响应所花费的总时间
调度算法:
- 先来先服务算法FCFS:简单,但是当短进程排在长进程之后时,等待时间变长长
- 短进程优先算法:有最优平均周转时间,需要预估CPU执行时间,可以用历史执行时间来预测未来,可能导致长进程一直在队列中等待,不合理
一个变种是短剩余时间优先算法,这样就可以抢占正在执行的进程 - 最高响应比优先算法:每次选择响应比R最高的进程,你等的时间越长,你的优先级越高
其中是等待时间,是执行时间 - 时间片轮转算法:时间片结束时,按FCFS算法切换到下一个就绪进程,
有额外的上下文切换
时间片太大,退化成FCFS;时间片太小,上下文切换太多,一般按经验选择10ms
公平,但是等待时间较差 - 多级队列调度算法MQ:就绪队列被划分成多个独立子队列,每个队列有自己的调度算法,队列间可以按照时间片或者优先级调度
- 多级反馈队列算法MLFQ:进程可以在不同队列间移动
- 公平共享调度FSS:保证不重要的组无法垄断资源
实时调度:要指定时间内完成
硬时限:错过任务时限会有灾难性后果
软时限:有时不能满足,则降低要求
- 速率单调调度算法:周期越短,优先级越高
- 最早截止时间优先算法
对称多处理器调度SMP:每个处理器运行自己的调度程序,调度程序对共享资源的访问需要同步
静态进程分配:进程从开始到结束都被分配到一个固定的处理器,这样调度的开销小
动态进程分配:所有处理器共享一个公共的就绪队列,这样调度的时候需要各处理器同步
优先级反置:高优先级进程长时间等待低优先级进程占用资源的现象
基于优先级的可抢占调度算法存在优先级反置
解决方法:
- 占有资源的低优先级进程,继承申请资源的高优先级的优先级
- 优先级天花板协议:占用资源进程的优先级和所有可能申请该资源的进程的最高优先级相同
4.4 同步互斥
程序并发执行的好处:共享资源、加速、程序模块化
原子操作atomic operation:不会出现部分执行的状态
临界区:进程中访问临界资源的一段需要互斥执行的代码
临界区的访问规则:
空闲则入,忙则等待、有限等待
临界区的实现方法:
- 禁用中断:没有中断,没有上下文切换,因此没有并发,禁用中断后进程无法停止
- 软件方法:通过共享变量,需要忙等待,浪费CPU时间
如果是多个线程: - 操作系统的抽象方法
硬件提供一些原子操作,比如
- 锁lock,有锁定和释放
- 测试和置位test-and-set指令:读值+写1
- 交换exchange
利用test-and-set指令可以实现自旋锁spinlock和无忙等待锁,但是可能出现死锁
4.5 信号量和管程
信号量semaphore是操作系统提供的一种协调共享资源访问的方法,用信号量表示系统资源的数量
是一种抽象的数据结构,由一个整形变量和两个原子操作组成,可以实现访问互斥和条件同步
管程moniter:多线程互斥访问共享资源的程序结构,正在管程的线程可以临时放弃管程
等待操作wait():将自己阻塞在等待队列中,唤醒一个等待者
释放操作signal():将等待对类中的一个线程唤醒
4.5.1 生产者-消费者问题
任何时刻只能有一个线程操作缓冲区(互斥访问)
缓冲区为空时,消费者必须等待生产者(条件同步)
缓冲区满时,生产者必须等待消费者(条件同步)
4.5.2 哲学家就餐问题
5个哲学家围着一个圆桌,桌子放着5支叉子,哲学家思考或者就餐,就餐就要同时拿起左右两边的叉子
4.5.3 读者-写者问题
读者:只读数据不改,允许多个读者同时读
写者:读取和修改数据,读-写互斥,写-写互斥
用管程实现
4.6 死锁
出现死锁的必要条件:
- 互斥
- 持有并等待
- 非抢占:资源只能在进程使用后自愿释放
- 循环等待:进程0等进程1,进程1等进程2……
通常操作系统忽略死锁,由应用程序处理死锁
死锁处理方法: - 死锁预防:限制对资源的请求,使得任何情况都不满足死锁的条件
- 死锁避免:利用额外的先验信息,动态检查资源分配状态,确保不会出现死锁,如银行家算法
银行家算法:客户贷款数量不超过银行拥有的最大值时,银行家应尽量满足客户需要 - 死锁检测:允许系统进入死锁,定期调用死锁检测算法来检测是否出现死锁
- 死锁恢复:一次终止一个进程直至死锁消除,按照进程的优先级、已运行时间等顺序终止
4.7 进程通信
通信方式:
- 间接通信:通过操作系统,利用消息队列,一个消息队列可以和多个进程共享
- 直接通信:两个进程之间建立共享通道
- 阻塞通信:一方在等待,只是接收/发送了信息
- 非阻塞通信
四种通信机制: - 信号
- 管道
- 消息队列
- 共享内存
管道:进程间通过内存文件的通信机制
共享内存:把同一个物理内存区域同时映射到多个进程的内存地址空间的通信机制
不同进程需要显式设置共享内存段,不过需要同步机制来协调数据访问
5 文件管理
文件:具有符号名,由字节序列构成的数据项集合
文件头:文件系统元数据中的文件信息,包括文件属性和文件存储位置和顺序
文件描述符:操作系统在打开文件表中维护的打开文件状态和信息
- 包括文件指针:每个进程最后一次读写位置
- 文件打开计数、
- 文件的磁盘位置:缓存数据访问信息
文件系统的基本操作单位是数据块
进程访问文件的模式:顺序访问、随机访问、索引访问
多进程如何同时访问共享文件??让应用程序自己解决
操作系统只允许内核修改目录,应用程序通过系统调用来访问目录。文件系统需要挂载才能被访问
**文件别名:**两个或多个文件名关联同一个文件
- 硬连接:多个文件项指向一个文件
- 软连接:快捷方式的形式,这样删除别名和删除其他文件是一样的
文件系统种类:
- 磁盘文件系统:如FAT、NTFS、ext2/3
- 数据库文件系统:如WinFS
- 日志文件系统:记录文件系统的修改/时间
- 网络/分布式文件系统,如:NFS
虚拟文件系统:不同的文件系统对上层的应用程序有相同的API接口
文件系统基本数据结构
- 文件卷控制块:每个文件系统一个:文件系统详细信息,如块大小,空余块
当文件系统挂载时进入内存 - 文件控制块:每个文件一个:文件详细信息,如访问权限,大小,拥有者
当文件被访问时进入内存 - 目录项:每个目录项一个:指向文件控制块,父目录,子目录
遍历到这个目录时进入内存 - 打开文件表:每个进程有一个打开文件表,系统有一个总的打开文件表
5.1 文件缓存
数据块使用后被缓存,两种数据块缓存方式:数据块缓存和页缓存
页缓存:在虚拟内存中文件数据块被映射成页,文件的读写操作被转换成对内存的访问
5.2 文件分配:分配一个文件数据块的位置和顺序
分配方式:
- 连续分配:文件读取表现好,但是会有碎片,数据增加会有问题
- 链式分配:用数据块链表存储:没有碎片,无法实现随机访问,可靠性差,破坏一个链,后面的都没有了
- 索引分配:给每个文件创建索引数据块:没有碎片,当文件很小,存储索引开销不可忽略
- UFS多级索引分配:前面10个直接索引,超过10个再加1级间接索引块,再超过就再加2级简介索引块
5.3 空闲空间组织和冗余磁盘阵列
用位图代表空闲数据块列表,表示第i个数据块空闲,但是这样空闲数据块链表太大
而链表的开销较大,不如用链式索引
磁盘分区:磁盘上一组柱面的集合,一个分区内可以减少寻道时间
文件卷:一个拥有完整文件系统实例的外存空间,通常常驻在磁盘的单个分区上
6 I/O管理
常见设备接口类型:
- 字符设备:键盘/鼠标、串口
- 块设备:以块为单位,如磁盘驱动器、光驱
- 网络设备:以太网、无线
CPU北桥连高速设备,南桥连I/O设备
CPU与设备的通信方式:轮询、中断或DMA
I/O地址
- 内存地址:MMU设置映射,将设备的寄存器/存储映射到内存地址空间
- 端口号:通过CPU的I/O指令访问I/O端口号
**磁盘调度算法:**通过优化磁盘访问请求顺序来提高磁盘访问性能
- FIFO算法
- 最短服务时间算法SSTF
- 扫描算法SCAN:磁盘在一个方向上移动,访问所有未完成的请求,知道磁壁到达该方向上最后的磁道
磁盘缓存:磁盘扇区在内存中的缓存