操作系统学习笔记

278 阅读7分钟

一、操作系统基础

  1. 操作系统是什么:管理硬件

image.png

  1. 计算机执行:取指(内存) - 执行(CPU)

image.png

  1. 计算机开机时都做了什么(将操作系统从磁盘中读取到内存,完成初始化)

boot:读取操作系统,将setup程序移动到0x0000地址处,执行setup程序

setup:读取系统配置,将system移动到0x0000处,进入保护模式(从16位机变成32位机),执行system程序

system:header.s(初始化gdt表,初始化页表) -> main.c(初始化:内存、桌面、时钟等)

  1. 操作系统接口:系统调用的一些函数(fork、excel、open等POSIX标准函数)
  2. 系统调用的实现:进入内核的手段

内核态:可以访问任何数据

用户态:不能访问内核数据

隔离手段:CPL(3)、DPL(0)

如何进入:中断指令int(int 0x80),int指令将使CS中的CPL改成0,进入内核

  1. 系统调用的核心:库函数

用户程序中包含一段包含int指令的代码

操作系统写中断处理,获取想调程序的编号:中断处理函数 system_call

操作系统根据编号执行相应代码

  1. 系统调用流程:

用户态(CPL=3):用户调用(printf)-> printf展成(int 0x80)-> 内核态(CPL=0):中断处理(system_call)-> 查表sys_call_table -> _NR_write(eax)= 4 -> 掉用sys_write

  1. 操作系统历史:

批处理:IBM7094(科学计算) -> IBM1401(银行) -> 多进程,任务切换和调度:IBM OS 360 -> 分时系统,任务切换,虚拟内存:MULTICS -> UNIX -> IBM PC

二、进程与线程

  1. CPU管理:多道程序交替执行,即并发(多进程)

进程就是进行(执行)中的程序,操作系统需要将进程记录好,按照合理的次序进行调度、分配资源

PCB(Process Control Block):用来记录进程信息的数据结构

  1. 多进程图像
    1. 多进程的组织:PCB+状态+队列

image.png

    1. 多进程如何交替:进程调度 -- 队列操作+调度+切换
    2. 多进程相互影响:地址空间分离(内存管理):映射表
    3. 多进程如何合作:进程同步(锁机制)

读写PCB(OS中最重要的结构,贯穿始终),操作寄存器完成切换,调度程序,进程同步与合作,地址映射

  1. 用户级线程:

进程=资源+指令执行序列,进程切换时资源和指令都会进行切换

线程:保留了并发的优点,避免了线程切换的代价(映射表不变,PC指针变)

核心是yield:切换TCB,切换栈

  1. 核心级线程

ThreadCreate是系统调用,内核管理TCB,内核负责切换线程

中断入口(进入切换) -> 中断处理(引发切换) -> schedule(内核栈) -> switch_to(内核栈切换) -> 中断出口

image.png

  1. 内核级线程实现

image.png

  1. CPU调度策略:以轮转为核心,折中和综合

SJF:短作业优先

RR:按时间片来轮转调度

优先级调度

  1. 进程同步与信号量

进程同步:保证多进程合作的合理有序

信号量:counter -> 信号量(记录线程状态,在某个时刻唤醒或使其睡眠)

  1. 信号量临界区保护:

多个进程共同修改引发问题 -> 找出进程中的临界区代码进行保护

临界区代码保护原则:

  • 互斥(如果一个进程在临界区执行,则其他进程不允许进入)
  • 有空让进(若干进程进入空闲临界区时,应尽快使一进程进入临界区)
  • 有限等待(从进程发出进入请求到允许进入,不能无限等待)

硬件原子指令法:使用硬件的原子指令TestAndSet实现CAS自旋

  1. 死锁处理

死锁的必要条件:

    • 互斥使用:资源的固有特性
    • 不可抢占:资源只能资源放弃
    • 请求和保持:进程必须占有资源,再去申请
    • 循环等待:在资源分配图上存在一个环路

死锁处理方法:

    • 死锁预防:破坏死锁出现的条件
      • 在进程执行前,一次性申请所有需要的资源,不会占有资源再去申请其他资源(编程困难、资源利用率低)
      • 对资源类型进行排序,资源申请必须按序进行,不会出现环路等待(资源浪费)
    • 死锁避免:检测每个资源请求,如果造成死锁就拒绝
      • 判断此次请求是否引起死锁——银行家算法(时间复杂度为O(mn²),效率低)
    • 死锁检测+恢复:检测到死锁出现时,让一些进程回滚,让出资源(同样使用银行家算法,效率低,同时回滚难度大)
    • 死锁忽略:不处理(死锁的出现不是确定的,又可以用重启动来处理死锁)

三、内存管理

  1. 内存的使用和分段:

重定位:编译时、载入时、运行时(将基地址存在PCB中,运行时动态计算物理内存地址)

image.png 分段:程序分段

image.png

内存分段(段表:LDT)

image.png

image.png

  1. 内存分区与分页:

分区:由于程序分段载入,所以需要找到每个程序段对应的空闲内存段,从而引出内存分区

  • 固定分区
  • 可变分区: 分区表、请求分配、释放内存、再次申请
    • 首先适配:获取空闲分区表的第一条数据
    • 最佳适配:获取最接近请求内存长度的空闲分区,向上取整(产生大量小碎片)
    • 最差适配:获取与请求内存长度相差最大的空闲分区(内存碎片较为均匀)

内存分区会导致大量内存碎片,内存使用效率低,要将内存充分利用,需要进行内存紧缩(将小碎片合并),需要耗费大量时间进行移动

分页:解决内存分区导致的内存效率问题

image.png

将内存按照每页4k的长度进行分页,同时页表寄存器(CR3)

image.png

  1. 多级页表和快表

页表的缺陷:为了提高内存空间利用率,页应该小,但页小对应的页表就会很大,空间占用也会随之增大

多级页表:页目录表+页表(提高了空间效率,但是增加了访问次数)

TLB:TLB命中时效率很高,但同时TLB很贵,通常只有【64, 1024】(程序多体现为循环、顺序结构,地址访问存在局部性,所以TLB存储最近几次访问的地址,命中率较高)

image.png

image.png

  1. 段、页同时存在:程序分段,根据段表获取空闲分区载入虚拟内存,虚拟内存中割出一部分保存页表去对应物理内存

image.png

  1. 内存换入换出

换入:请求调页 -> 当前页表没有映射 -> 调用int 0x14中断 -> 从磁盘中载入请求页 -> 放入页表 -> 继续执行

image.png 换出:

FIFO:先进先出

MIN:选最远将使用的页淘汰,最优方案,但我们无法知道未来的事情

LRU:选最近最长一段时间未使用的页淘汰(最近最少使用),公认最好算法,但无最佳实现

LRU近似实现:Clock算法:每次访问一页时,硬件自动设置一个引用位,选择淘汰页时,扫描引用位,是1时清0并继续扫描,是0时淘汰,同时有一个扫描指针用来定时清除R位,扫描指针要比选择淘汰页的指针快

image.png

四、设备驱动与文件系统

  1. I/O与显示器

外设工作原理:

image.png

printf工作流程:

image.png

pos每次加2(内容、属性)

  1. 键盘

image.png

image.png

  1. 生磁盘的使用

image.png

image.png

磁盘IO过程:控制器 -> 寻道 -> 旋转 -> 传输

使用磁盘演变流程:磁盘访问时间 = 写入控制时间 + 寻道时间(慢) + 旋转时间 + 传输时间

image.png

直接使用:往控制器中写柱面、磁头、扇区、缓存位置(程序 - sec、head、cyl -> 磁盘控制器)

通过盘块号读写磁盘:程序 -block-> 磁盘驱动 -sec、head、cyl-> 磁盘控制器

多个进程通过队列使用磁盘:进程1/进程2 -> 请求队列 -> 磁盘驱动 -sec、head、cyl-> 磁盘控制器

      1. 进程"得到盘块号",算出扇区号(sector)
      2. 用扇区号make req, 用电梯算法add_request
      3. 进程sleep_on
      4. 磁盘中断处理
      5. do_hd_request算出cyl、head、sector
      6. hd_out调用outp(...)完成端口写

磁盘调度算法:

FCFS:先进先出。最直观、最公平的调度

SSTF:短寻道优先

SCAN:SSTF+中途不回折,每个请求都有处理机会,电梯算法

C-SCAN:SCAN+直接移动到另一端,两端请求都能很快处理