操作系统

第一章 介绍

1.2 计算机系统组织

1.2.1 计算机系统操作

  • I/O设备可以和CPU同时工作

  • 每一类I/O设备都有自己的控制器

  • 每一个控制器都有一个缓冲区

  • CPU将数据在缓冲区和内存之间移动

  • I/O操作将数据从I/O设备移动到缓冲区

  • 控制器通过中断告知CPU自己已经完成了I/O操作。

  • 中断的类型

    • trap: trap类型的中断因软件产生,程序执行过程中出现错误(算数移除,访存越界)或用户请求时会发生此类型的中断。
    • interrupt: interrupt类型的中断因硬件产生。I/O完成,计时器到时,硬件故障时会发生此类型的中断。
  • 中断发生时要:

    1. 启动中断服务程序
    2. 保存现场
    3. 屏蔽其他中断
  • 操作系统是由中断驱动的(换言之,操作系统从不自己主动做事情)。

  • 处理中断

    1. CPU保存寄存器状态和程序计数器
    2. 判断发生了哪种中断
    3. 调用对应的代码段处理中断
  • 中断循环

    1. 处理器在取下一条指令之前,先判断有没有中断
    2. 若没有中断,则继续取下一条指令执行当前程序
    3. 若有中断,暂停现有程序,运行中断处理程序
  • 中断时间线
    挺好的一张图,看懂就好
    中断时间线

1.2.2 存储结构

计组那一套

  • 分级存储
    • 主存
    • 第二存储
    • 磁盘
    • 磁带

1.2.3 I/O结构

  1. Programmed I/O(有规划的I/O,我自己起的名字)
    Programmed I/O
    • CPU没有拿到它想要的那一个word之前,就一直等着。一直等I/O设备的status变成可用,然后给它读了那一个word,然后才结束。
  2. Interrupt-Driven I/O(中断驱动的I/O)
    Interrupt-Driven I/O
    • CPU给I/O设备一个“我要用你了”的信号,然后就去做别的事情。等I/O设备准备好了(或者出现了故障),会中断CPU的进程,然后为CPU做它想要做的事情。
    • 同步I/O:I/O工作开始之后,一直等到I/O完成,控制权才返还给用户。
    • 异步I/O:I/O工作开始之后,控制权不等到I/O完成就返还给用户。
  • 在实际的I/O工作开始前,到底是不是在坐等I/O设备可用是区分Programmed I/O和I-D I/O的标准。

  • 在I-D I/O中,是否坐等I/O工作完成,是区分同步和异步I/O的标准。

  • 有两个东西方便实现上述功能

    1. 设备状态表:设备处于什么状态
    2. 系统调用:操作系统要怎么用设备
  • DMA(Direct Memory Access)

    • 高速(与存储器读写速度相近的)I/O设备可以通过DMA一块一块的直接进行读写内存操作,中途不加CPU的干预
    • CPU只在I/O开始和结束时介入。
    • 每次读写一块数据时,CPU只在结束时被中断一次。
    • 期间CPU可以做其他事情。
  • I/O通道控制程序

    • 与DMA类似
    • CPU通过I/O指令控制I/O设备
    • I/O指令包括:通道号,I/O设备号,通道程序的首地址
    • 通道程序由若干通道指令组成
    • 当CPU需要一系列I/O操作时,只需要向I/O通道发送一条I/O指令即可。
    • 通道程序举例
      通道程序举例
      • P:=1时代表是通道程序的最后一条指令
      • R:=1时代表这一条指令是处理当前记录的最后一条指令

1.4 操作系统结构

  • 单线编程:再执行一个任务时,到了I/O环节,CPU总是要等I/O进行完毕再进行下一个动作,CPU和IO设备永远不会同时工作。
  • 多线编程:保证CPU一直在运转,将所有要做的工作存起来。在执行一个任务到了不得不等I/O的环节时,操作系统切换到另一个工作。
    Multiprogramming
  • 时分复用
    • CPU频繁的不同工作之间切换,确保用户可以在一个进程运行的期间和它交互
    • 至少有一个工作在内存中执行
    • 多个工作同时执行时要按照多线编程的方式选择工作进行
    • 如果要进行的进程无法放进内存中,需要把内存中的东西移出去(有可能把别的工作移出去)。
    • 多用户通过终端同时访问
  • 时分复用系统的特点
    • I/O规划由操作系统安排
    • 操作系统为不同的工作分配内存
    • 设立虚拟内存,为了使工作不只能在内存中进行
    • 文件系统实现磁盘管理
    • 安排CPU要做的事情,避免死锁
    • 分配资源

1.5 操作系统行为

  • 现代操作系统是由中断驱动的
  • 硬件触发的中断叫做Interrupt,软件叫做trap或exception
  • 双模式行为:硬件支持系统处于两种状态下
    1. User mode: 用户执行
    2. Monitor mode: 系统执行
  • 双模式行为:
    • 硬件设置标志位:0为Monitor mode,1为User mode
    • 可以分辨当前处于什么模式
    • 某些有特殊权限的指令只能在kernel mode下执行
    • 一个system call就会转移到kernel mode,从system call返回时转移到user mode
  • 设立计时器防止资源一直被某一进程占用
    • 操作系统维护一个倒计时的计时器
    • 当倒计时为0时,触发一个中断
    • 在一个进程重获控制权时开始计时,在一个进程执行的时间超过预期时中断
    • 用于改变这个计时器值的指令是一种特殊权限指令

1.6 进程管理

  • 进程是一个系统正在执行的程序,是系统工作的单位。
  • 进程需要资源
  • 进程在结束时需要把资源归还
  • 单线程的进程只有一个PC,多线程的进程每个线程都有一个PC
  • 不同处理器上同时运行着多个进程
  • 操作系统需要管理以下和进程有关的事件
    • 创建/销毁用户/系统进程
    • 挂起/恢复执行进程
    • 同步进程
    • 进程通信
    • 防止死锁

第二章 操作系统结构

2.1 操作系统提供的功能和服务

  1. 一类用于方便用户使用
    • 用户交互,程序执行,I/O,操纵文件,进程间通信,错误检测
  2. 一类用于高效执行自己的业务
    • 分配资源,统计,保护
    • 多用户可以通过分配资源来提高效率

2.2 用户与系统交互的方式

  • CLI 命令行
    • MS-DOS在内核中实现,内置命令
    • Windows和UNIX在系统程序中实现
    • Windows的命令控制界面
      • 运算符:&,&&,||,(),;,%1
      • 批处理文件:.bat和.cmd
  • GUI 图形化界面
  • 操作系统汉化
    • CCDOS:第一台长城机汉字操作系统
    • HHBIOS:CCDOS的进阶版
    • UCDOS:企业研发,性能优良,灵活方便
    • 中文之星:Windows外围汉化代表
  • 语音控制(VUI)
  • 图像
  • 手势
  • 脑机

2.3 系统调用

  • 对于系统提供的服务的编程式交互
    • 例:写一个打开a文件,把a文件中的内容写入b文件
  • 通常使用高级编程语言
  • 多数由高级程序提供的接口(API)实现,而不是直接进行系统调用
  • API会提供一系列的函数方便编程者使用
  • 常见的API:
    • Windows API:Windows
    • POSIX API:UNIX,LINUX,macOS
    • Java:JVM
  • API比直接进行系统调用有着更好的迁移性,且屏蔽了一些不需要的细节。
  • API
    Windows API:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /*
    * @retrun BOOL
    * @name ReadFile
    * @param file The file to be read
    * @param buffer A buffer where the data will be written or read from
    * @param bytes to read The number of bytes to be read next time
    * @param bytes read The number of bytes read to the buffer during the last read
    * @param ovl Indicates if overlapped I/O is used
    */
    BOOL ReadFile(
    HANDLE file,
    LPVOID buffer,
    DWORD bytes To Read,
    LPDWORD bytes Read
    LPOVERLAPPED ovl
    );
    UNIX and Linux:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <unistd.h>

    /*
    * @retrun ssize_t
    * @name read
    * @param fd The file descriptor to be read
    * @param buf A buffer where the data will be read into
    * @param conunt The maximum number of bytes to be read into the buffer
    */
    ssize_t read(int fd, void *buf, size_t count);
  • 支持运行时的系统会专门有一个系统调用交互
    • 有一个系统调用索引表,每一个系统调用都对应一个数字
    • 系统调用交互会:
      • 屏蔽API里的系统调用
      • 启用OS中必要的系统调用
      • 返回结果
  • 用户并不知道系统调用是怎么做的,他们只需要知道怎么调用API和获得返回值就可以了。
  • 向系统调用传递参数的三种方式
    1. 寄存器
    2. 内存块
    3. 栈:程序入栈,OS出栈

2.4 系统调用的类型

  1. 进程控制
  2. 文件管理
  3. 设备管理
  4. 信息维护:获取,设置系统时间,文件属性
  5. 交流:进程间
    1. 内存共享:借用内存共享块通信,不需要协助,不方便进程间同步,安全性差,高速量大
    2. 消息传递:用send和receive,包含系统调用,必须提前建立连接,效率较低但是可以保持同步,用于交换信息量较少的数据,安全性好
  6. 保护:设置资源权限

2.5 系统程序

  1. 文件管理
  2. 状态信息
  3. 文件编辑
  4. 编程语言支持
  5. 程序加载和执行
  6. 用户,进程,系统间通信
  7. 系统工具
  8. 后台服务:自启动

2.6 操作系统的设计与实现

  • 并不存在一个完美的解决方案
  • 不同操作系统的内部原理相差甚远
  • 从理清目的和特点出发
  • 受硬件类型,操作系统类型(批处理,时分复用…)影响
  • 难以具体化目标
    - 用户:易用,性能强大,可靠,快速
    - 系统:易实现,易维护,可靠,高效,可迁移

  • 设计和实现一个操作系统是软件工程中极具创造性的工作
  • 目标(Policy)手段(Machanism)中分离出来
    • 二者分离是实现灵活性的重要途径
  • 操作系统的实现
    • 相差甚远
    • 时间发展顺序:汇编语言————Alogol,PL/1————C,C++
    • 实际上是多种语言的混杂,底层汇编,主体C,系统程序C/C++,Python,PERL,shell scrpits
    • 更多的高级语言会导致
      • 硬件之间的迁移性好
      • 运行速度变慢
    • 仿真可以让操作系统运行在非原生的硬件上
  • 影响操作系统性能的重要因素:优秀的数据结构和算法
  • 只有小部分代码的性能对系统总体性能有至关重要的影响
    • 中断处理,I/O处理
    • 内存管理,CPU管理
  • 在可以正常工作后,优化瓶颈:将其转换为等价的汇编语言

2.7 操作系统结构

2.9 迁移操作系统

  • 一个SYSGGEN文件用来描述操作系统所需的硬件参数
    • CPU,内存大小,设备,缓冲区大小
  • 迁移操作系统的方式
    • 复制并修改原本操作系统的源代码
    • 选择之前操作系统库中的部分功能
    • 配置一个合适的表用来描述系统

2.9 启动操作系统

  • Booting:通过加载内核启动计算机
  • Bootstrap Program:一小段在ROM中的程序,定位内核,将其加载进内存,启动执行
  • 两步走
    1. bootstrap loader:诊断初始化系统,将boot program写入内存准备执行
    2. boot program:将整个操作系统加载进内存开始执行

第三章 进程

3.1 进程概念

  • 执行中的程序进程

  • 程序:静态存储在磁盘上的可执行文件

  • 进程:程序加载进内存开始动态执行成为进程

  • 一个进程内包括:

    • 程序代码
    • 数据区:全局变量
    • 堆:动态分配的内存
    • 栈:临时变量,包括:函数参数,返回地址,局部变量
    • 当前操作:程序计数器
  • 进程在执行过程中会改变状态

  • 一个进程总是在以下几个状态之一:

    • 新创建
    • 正在执行
    • 等待:等待某个事件的发生
    • 就绪:准备加载到一个处理器开始执行
    • 终止
  • 一个处理器只能同时执行一个进程,其他进程都在等待和就绪
    进程状态

  • 每个进程都由一个进程控制块(PCB)反映

  • 一个程序块中包含:

    • 进程状态
    • 程序计数器
    • CPU寄存器
    • CPU给它的规划:优先级,执行队列
    • 内存管理信息
    • 统计信息:总共用了多少CPU时间,当前时间片用了多少时间,时间限制是多少…
    • I/O信息:打开的文件,分配给进程的I/O设备
    • 进程ID
  • 进程在状态之间转换的时机

    • 时钟打断:已经执行到了最大时间
    • I/O打断
    • 内存错误:访问到虚拟内存,必须从外存把数据带进来
    • 异常
    • 系统调用
  • 一个进程中可以有多个线程

    • 多个线程可以同时进行
    • 在PCB中记录多个程序计数器

3.2 进程调度

  • multiprogramming的目的:最大化CPU利用率

  • 时分复用的目的:让用户可以在一个进程执行时与它交互

  • 调度队列

    • 工作队列:系统中所有进程
    • 就绪队列:系统中所有就绪的进程
    • 一般用链表存储
  • 设备队列:每个设备有一个属于自己的队列,用于记录等着要使用它的进程
    队列图

  • 长周期调度(job scheduler)

    • 选择进入就绪队列的进程
    • 不频繁被打断
    • 长周期调度要控制同时在内存里的进程数量
  • 短周期调度(CPU scheduler)

    • 选择下一个要执行的进程
    • 频繁被打断
  • 进程可以分为以下两类

    1. 绑定I/O的进程
    2. 绑定CPU的进程
  • 绑定I/O的进程多了,就会有很多进程卡在等待状态,就绪队列的进程很少,CPU调度不需要做什么工作

  • 绑定CPU的进程多了,很多进程都会在就绪状态,设备队列的进程就很少,硬件会大量闲置

  • 中周期调度(medium term scheduler)

    • 将就绪队列和设备队列里的进程换进(到内存)换出(到磁盘),让两个队列比较均衡
    • CPU处理的比I/O设备快,所以所有进程可能都在设备队列
    • 这时候把设备队列里的进程换出,状态变为挂起等待
    • 新增两个状态
      1. 挂起等待
      2. 挂起就绪
    • 换出的原因:
      • CPU需要为一个要执行的进程腾出一些内存空间
      • 系统怀疑有一个进程产生了异常
      • 用户主动要求
      • 一个进程是每过一段固定时间才执行
      • 父进程要求
  • 语境切换
    每次CPU切换要执行的进程时,要进行语境切换。一个进程的语境存储在PCB里,语境切换包括以下步骤:

    1. 保存处理器的执行环境:包括程序计数器和寄存器状态
    2. 更新当前正在执行的进程PCB
    3. 把PCB挪到它应该去的地方
    4. 选择另一个要执行的进程
    5. 更新要执行的进程的PCB
    6. 更新内存管理数据结构
    7. 恢复要执行的进程的语境
  • 语境切换是顶级操作:CPU在这个过程中不做任何实际的工作

  • 切换速度取决于硬件

3.3 进程操作

创建进程

  • 创建进程的原因
    1. 执行一项批处理工作
    2. 用户登录
    3. 要打印东西
    4. 被其他进程创建
  • 创建进程的步骤
    1. 给新进程分配一个ID
    2. 给新进程分配内存空间
    3. 初始化PCB
    4. 进行合适的链接:让需要知道这个进程存在的东西都知道它被创建了,比如把它连进CPU调度链表
    5. 创建别的数据结构:比如一个统计信息表
    6. 确定资源共享方案:共享父进程的所有资源,共享父进程的部分资源,不和父进程共享资源
    7. 当一个进程被创建时,他可能包含着从父进程传给它的初始化参数
  • 执行时的两种可能:
    1. 与父进程同步执行
    2. 父进程等待他的一些子进程结束后继续执行
  • 地址空间的两种可能:
    1. 与父进程完全相同
    2. 有一段程序专门加载子进程的地址空间
  • PPT上的练习

终止进程

  • 终止进程的原因
    • 正常执行结束
    • 执行时间超过限制
    • 内存不可用
    • 越界访问
    • 越权操作:尝试写入只读文件
    • 算数异常:分母为0
    • 等待(I/O)时间超过最大值
    • I/O失败
    • 错误指令
    • 越权指令:用户进程试图执行只有内核才能执行的指令
    • 数据异常:类型不匹配
    • 操作系统介入:死锁
    • 父进程终止
    • 父进程要求子进程终止
  • 进程执行了最后一条指令,请求操作系统删除它
    • 将数据还给父进程
    • 收回分配的资源
  • 父进程要终止子进程的原因
    • 子进程用了超出给它分配的内存空间
    • 分配给子进程的任务已经不再需要了
    • 父进程自己要终止

3.4 进程间通信

  • 独立进程不会影响其他进程执行,也不会被其他进程执行影响

  • 合作进程会影响其他进程执行,也会被其他进程执行影响

  • 两个基础模型

    1. 共享内存:可以达到通信的最高速度和便利性,可以以内存读写的速度进行通信
    2. 通信管道:适用于数据量小的通信,因为不需要考虑读写冲突;跨计算机通信更好实现
  • 共享内存系统——生产者-消费者问题

    • 一个经典模式:生产者进程生产数据,消费者进程消费数据
    • 我们要提供一个缓冲区,让生产者把数据放进来填满,让消费者搬空
      • 生产者生产和消费者消费可以同时进行
      • 两者必须同步(synchorize)
    • 两种缓冲区
      1. 无界缓冲区
      2. 有界缓冲区:循环队列
  • 通信管道——IPC

    • 通信并同步他们的执行节奏
    • 建立一个管道,然后通过send()receive()通信
    • 管道的介质
      • 物理介质:共享内存,硬件总线,网络
      • 逻辑介质:逻辑属性
    • 直接通信
      • 进程之间必须显式指定通信双方的名字
      • 两个通信进程之间有且仅有一根管道(可单向可双向)
    • 间接通信
      • 进程之间依赖邮箱通信,一个进程把数据放到信箱里,另一个进程来取
      • 一个信箱可能有多个进程使用
      • 两个进程之间可能用多个信箱
    • 如何杜绝间接通信中的冲突问题
      1. 最多允许两个进程共享一个信箱
      2. 最多同时允许一个进程调用receive()函数
      3. 让系统随机选择一个接收者,让发送者知道谁拿到了
    • 一个信箱可以被操作系统或者进程占用
    • 如果这个信箱是被进程创建的
      • 这个进程只能用这个信箱接受信息
      • 别的进程只能往这个信箱发送信息
    • 如果这个信箱是系统创建的:不属于任何进程
    • 操作系统向进程提供以下几种操作
      • 创建和删除一个信箱
      • 从信箱中接收消息,发送信息到信箱
    • 同步/异步
    • 限制发送者
      • 通道0容量:发送者必须等接收者可以接收的时候才能发
      • 通道n容量:发送者必须等通道有空闲了再发
      • 通道无限容量:发送者的发送不受任何限制

操作系统
https://heyewuyue1.github.io/2022/09/10/OperatingSystem/
作者
何夜舞月
发布于
2022年9月10日
许可协议