操作系统
作用:管理软硬件资源
启动过程:
按下电源按钮,会向CPU发一个reset信号
BIOS程序存在 ROM 里面
BIOS启动
步骤:
1.上电自检
2.初始化硬件设备
3.搜索一个操作系统来启动,例如:硬盘(硬盘第一个扇区称为主引导记录 MBR [分为引导程序 boot loader] 、分区表)、U盘
4.找到有效设备后,把第一个扇区的内容拷贝到内存中,起始地址是 0x00007c00,然后跳转到这个地址处
PS:异常源自 处理器内部,中断源自处理器芯片外部
陷阱和系统调用
在8086用户模式中 执行syscall 指令就可以调用内核模式的系统调用的功能
中断、异常、陷阱的作用可以切换用户态和内核态,让用户态可以去访问硬盘
在多个进程中,每一个进程都有内核虚拟内存,这样方便在你用户态代码下直接系统调用 转换为内核态,也可以被称为切换进程
进程和线程
进程:就是一个正在运行程序的抽象
在Linux 中 创建进程使用 系统调用 fork() + execve()
进程的创建
什么时候创建?
1.系统初始化(操作系统启动)
2.正在运行的程序执行了创建进程的系统调用 (fork)
3.用户请求创建一个新进程
4.一个批处理作业的初始化
进程状态
进程被创建后,进入就绪状态,等待被调度执行
进程三种状态:运行、就绪、阻塞
进程终止: 正常退出,出错退出,严重错误,被其他竞争kill掉
进程调度算法
1.先来先服务 (弊端:如果在前面的任务比较长的,那他的平均周转时间比较高)
2.最短任务优先(非抢占) 先运行最短任务,然后是次短的任务
3.抢占式最短完成时间优先 每当有新的任务到达时,会确定剩余任务和新任务中,谁的剩余时间最少,然后调度该时间最少的任务
4.高响应比【(等待时间 + 执行时间) / 执行时间】 优先调度算法
看响应比高的 优先执行(看公式判断即可)
交互式系统调度
时间片调度 给固定时间,如果在固定时间内没有执行完,那么就换另一个进程
进程切换(上下文切换)
切换需要干什么?
1.保存当前进程的上下文 (保存通用寄存器、浮点寄存器、程序计数器(PC)、程序状态字、用户栈、内核栈、描述地址空间的页表、当前进程信息的进程表)
2.恢复某个之前被抢占的进程的被保存的上下文
3.将控制传递给这个新恢复的进程
线程
许多应用中,存在许多同时发生的多种活动
线程包实现
1.用户进程管理线程(主要是将线程包放到用户空间中)
2.内核管理线程
3.混合实现 (了解即可)
临界区
预防临界区出现的差池:
1.任何两个进程不能同时处于临界区
2.不应对CPU的速度和数量做任何假设
3.临界区外运行的进程不得阻塞其他进程
4.不得使进程无限期等待进入临界区
解决临界区的办法:
1.屏蔽中断 对于内核态比较方便 原理:不让发生时钟中断 或者 其他中断 不让切换内核态,也就不会切换进程
2.Peterson 算法 原理:将进程数量存在一个数组内,然后让另一个忙等,等在CPU的进程执行完后另一个忙等的才有机会进入执行
3.TSL指令(锁住内存总线) 步骤:读内存字(将内存读入寄存器),写内存字(写入内存)
4.Swap指令
上述方法弊端:总是等待
信号量(是一个整形计数器)
定义:用于控制多进程或多线程并发访问共享资源的同步机制
为什么要信号量?
因为在多进程或多线程程序中,共享资源的并发访问可能导致竞争条件,信号量可以协调这个竞争
信号量主要操作: P(用于请求资源) 和 V(用于释放资源)
//整数型信号量
int s = 1
void wait(int s)
{
while(s <= 0){}
//弊端:一直在等待
s--;
}
//这个表示 如果当前资源可用,那就占用这一块 s--
void signal(int s)
{
s++;
}
//最后占用完需要释放掉这个资源
//记录型信号量
typedef struct
{
int value;
Struct process *L;
}semaphore
void wait(semaphore S)
{
S.value --;
if(S.value < 0)
{
block(S.L);
//进入阻塞态
}
}
void signal(semaphore S)
{
S.value ++;
if(S.value <= 0)
{
wakeup(S.L);
}
}
经典同步问题
应用:
1.读者——写者问题
原理:允许多个用户同时查看座位的分配,但是正在预定座位的客户必须拥有对数据库的独占访问
2.哲学家就餐问题
管程 (monitor)
原理:把信号量和操作封装在一个对象的内部(也就是把共享变量共享在一个模块下)
PS:注意:确保每次只有一个进程在管程内处于活动状态
实现方法
需要用条件变量和 wait 和 signal condition x
具体流程:
1.当操作 x.wait()调用这个操作的进程会被挂起
2.当操作 x.signal() 才会把这个调用x.wait()的进程停止
如果没有前面的x.wait()这一操作,那么后面的x.signal()就没有什么用了
管程中的wait()和signal()方法 都跟信号量中的不一样!!!!
死锁
定义:指多个进程在运行过程中争取资源而造成一种僵局,当进程处于这种状态时,若无外力作用,这些进程都无法再向前推进
发生死锁的条件:(需要通过同时满足)
1.互斥条件
2.请求和保持条件
3.不可抢占资源 (进程已获得的资源不能被强制性抢占)
4.环路等待资源
死锁检测和恢复
检测的算法实现:
将数据放入链表中,一个个去遍历,如果节点相同证明有环路,所以就检测到死锁的产生
死锁的恢复
1.利用抢占恢复
2.利用回滚时间 (周期性对进程进行检查点检查) 相当于存档,可以分析发生死锁的原因
3.通过杀死进程恢复
安全状态和不安全状态
区分这两个的最主要就是 看进程是否能全部执行完
死锁避免——银行家算法(伪算法)
主要是对请求的满足是否会导致进入不安全状态(不是死锁哦),如果导致不安全状态就拒绝该请求,否则就满足该请求
死锁预防
1.破防互斥条件 比如假脱机打印技术,可以允许多个进程同时产生输出
2.破坏请求和保持 请求发放所有资源,如果一个资源或者多个资源正在被使用,那么就不进行使用,进程进行等待
3.破坏不可抢占条件 通过将设备虚拟化,避免发生混乱
4.破坏环路等待条件 当一个进程请求资源时,先暂停释放其当前占用的全部资源,可以对资源编号,通过对序列判断再决定资源分配
虚拟内存
有一个一开始让我很困惑的问题,就是为什么操作系统需要使用虚拟内存印射到物理内存这一方案?
因为当可用内存完全消耗完时,操作系统可以通过磁盘空间扩展可用内存,也就是将数据交换到硬盘,为新进程提供相应的空间
虚拟空间的大小取决于虚拟空间的位数
将虚拟空间划分以下就叫页
记录虚拟地址和物理地址的关系,就用页表(存在内存中)
虚拟页和物理页大小是一样的
虚拟页已经缓存在内存中叫 cache,不在内存中但在磁盘上分配了就是Uncatched,这时候valid = 0,就发生了缺页,需要触发中断
虚拟页都不在磁盘中的叫 Unallocated
虚拟地址拆分为:
虚拟页号 (剩余bit - 12bit) 虚拟页偏移量(12bit)
因为每个进程会有一张单独的页表,而进程又是数不胜数的,于是为了优化页表在内存中的存储范围,我们采用多级页表以此来减少内存
多级页表结构:
目录号 页号 页偏移量
多级页表的优势:比单级页表更节省空间,因为在单级页表中,你的每个进程独占一个页表,那么有N个进程就有N个页表;而多级页表就可以只有一张表,但是在上面集成了很多很多的页,工作流程就是从初始页表出发,一直不断的迭代去找相应页的位置,直到最后一张页访问完就拿到真实的内容了
页面置换算法
1.FIFO页面置换 最新进入的页面放在表尾,最早进入的页面放在表头
弊端: 随着 分配页面数量的增加,缺页错误率可能会增加
2.最优页面置换 置换在一段很长时间不会使用的页面即可
弊端:你怎么知道你的页面什么时候被替换?
3.最近最少使用 (LRU) 在发生缺页中断时,置换未使用时间最长的页面,最近最多使用的页面在表头,最近最少使用的在末尾
弊端:代价比较大,需要每次更新链表
4.时钟页面置换 每一页有一个访问位,若该页面被访问,则置访问为 = 1(可以优化时钟页面置换算法)
页面分配策略
固定分配,局部替换
可变分配,全局置换
可变分配,局部置换
段页式
在x86-32系统中有,既分段,又分页
文件系统
文件结构
字节序列、记录序列、树
文件类型
普通文件(ASCll码、二进制码)、目录文件、特殊文件(字符特殊文件、块设备特殊文件)
文件访问
顺序访问、随机访问
磁盘分配空间(因为文件存储在磁盘上)
1.连续分配(类似数组) 支持顺序访问和随机访问 顺序访问速度快
需要连续的存储空间
2.链式分配 只适用于顺序访问 访问效率低
3.索引分配 将所有指针放在一起
支持随机访问,没有碎片;但索引块浪费空间
索引分配效率比较高的方式是 类似于多级页表的方式,就是将很多个物理块放入一个大块中,比如第一个索引表存放第二个索引表的那个数据的块地址,一层层迭代访问(只有在文件特别大的时候才会开多级索引块,如果文件不大就直接用数据块即可)
但这里其实有个比较跟多级页表不一样的地方他可以混合索引,顾名思义就是将经常访问的数据放在第一个索引节点下面,(注意这里是在一个索引块里面)剩余的空间拿来放间接数据块的地址
文件操作和目录文件
文件操作
1.创建文件 可以通过系统调用open实现
int fd = open("path",O_CREAT|O_WRONLY|O_TRUNC)
fd 是 文件描述符(可以理解为是一种权限,允许执行某些操作)
2.读文件 size_t read(int fd ,void *buf,size_t n);
3.写文件 size_t write(int fd ,const void *buf,size_t n);
4.删除文件 int close(int fd);
5.截断文件
目录文件
文件系统通常使用目录记录文件位置
目录包含一个文件名的列表,每个文件名对应一个inode编号
每个文件名称为目录项(本质结构体),每个名字到inode 的映射称为链接
struct dirent
{
ino_t d_ion; //记录索引编号
char d_name[256];//记录文件名
}
目录操作
1.创建目录
2.删除目录
3.打开目录和关闭目录
4.读目录项
5.文件链接 目录中每个名字到索引节点的映射方式叫链接 分为软链接(符号链接)和硬链接)
硬链接和copy的区别
硬链接的inode索引节点一样,在磁盘上只存在一份文件
而copy inode 索引节点不一样,在磁盘上存在两份文件
空闲空间管理
一般常用位图法
用一个字节拆分8位(相当于一位表示一个块),用0表示磁盘块空闲,用1表示磁盘块占用
磁盘调度算法
柱面(相邻两个磁道构成柱面)、磁道、扇区组成磁盘的物理地址
磁盘使用
1.分区 将磁盘分为有柱面组成的多个分区
2.逻辑格式化(创建文件系统(包含空闲空间、已分配空间、一个初始为空的目录))
磁盘调度
1.FCFS(先来先服务)
2.SSTF (最短寻道时间优先) 选择最接近磁头位置的待处理请求
注意:不是时间最少哈
3.SCAN调度(电梯算法) 磁臂从磁盘的一端开始,向另一端移动
4.C-SCAN调度(循环扫描) 当磁头到达另一端时,它立即返回到磁盘的开头,并不处理回程的请求
设备管理
1.程序I/O方式
2.中断驱动I/O控制方式
3.直接内存访问(DMA)
4.I/O通道控制方式
I/O软件层次
用户级I/o软件
与设备无关的操作系用软件 主设备号和从设备号
设备驱动程序 每个设备驱动程序通常处理一种类型的设备
中断处理程序
硬件
PS:设备驱动程序与设备控制器所有通信都通过总线

被折叠的 条评论
为什么被折叠?



