操作系统之 进程和线程

进程

指一个具有一定独立功能的程序在一个数据集合上的一次动态执行的过程

进程的组成

进程包含了正在运行的程序所有状态信息

  • 代码
  • 数据
  • 状态寄存器
    • CPU 状态 CR0
    • 指令指针 EIP
  • 通用寄存器
  • 进程占用的系统资源
    • 打开文件
    • 已分配内存

进程的特点

  • 动态性
    • 可动态创建 结束进程
  • 并发性
    • 进程可以被独立调度并占用CPU运行
  • 独立性
    • 不同进程的工作互不影响
  • 制约性
    • 因访问共享数据 资源 进程间的同步而产生制约

进程与程序的联系

进程是操作系统处于执行状态下的程序的抽象 同一个程序的多次执行
过程对应为不同的进程

  • 程序 = 文件(静态可执行文件)
  • 进程 = 执行中的程序 = 程序 + 执行状态
进程执行需要的资源
  • CPU 执行指令
  • 内存 保存代码和数据

进程与程序的区别

  • 进程是动态的 程序是静态的
    • 程序是有序代码的集合
    • 进程是程序的执行 进程有内核态和用户态
  • 进程是暂时的(是一个状态变化的过程) 程序是永久的(保存到文件系统时)
  • 进程与程序的组成不同
    • 进程的组成包括程序 数据 进程控制块

进程控制块 (PCB Process Control Block)

操作系统管理控制进程运行所用的信息集合 (操作系统用 PCB 来描述进程的基本情况以及运行变化的过程)

  • PCB 是进程存在的唯一标识
    • 每个进程都在操作系统中有一个对应的 PCB

进程控制块存些什么?

  • 进程标识信息 (PID)
  • 处理机现场保存 (调度之前需要 保存上下文 保存其他寄存器 以便下次调度回来的时候使用)
  • 进程控制信息 (调度优先级)
    • 调度和状态信息 (调度进程和处理机使用情况)
    • 进程间通信信息
    • 存储管理信息 (指向进程映像存储空间数据结构 占用的存储空间用完以后还给操作系统)
    • 进程所用资源 (进程使用的系统资源 打开文件)
    • 有关数据结构连接信息 (与PCB相关的进程队列 不同的状态处于不同的进程队列)

PCB_Context

进程控制块的组织 (数据结构实现)

链表

同一状态的进程其 PCB 成一链表 多个状态对应多个不同的链表

  • 各状态的进程形成不同的链表 就绪链表 阻塞链表
索引表

同一状态的进程 归入一个 索引表(由索引指向PCB) 多个状态对应多个不同的索引表

  • 各状态的进程形成不同的索引表 就绪索引表 阻塞索引表

PCB_Data_Structure

进程状态

  • 进程创建 操作系统分配给进程所需要的资源 构建 PCB
    • 系统初始化时
    • 用户请求创建一个新进程
    • 正在运行的进程执行了创建进程的系统调用
  • 进程执行
    • 进程创建完后 会放入就绪队列 等待 CPU调度
    • 内核选择一个就绪的进程 让它占用处理机并执行
  • 进程等待(阻塞) 进程等待是进程本身发起的 不是外部让它去等待的
    • 请求并等待的系统服务 无法马上完成
    • 启动某个操作 无法马上完成
    • 需要的数据没有到达
  • 进程抢占
    • 高优先级进程就绪
    • 进程执行时间片用完
  • 进程唤醒 进程唤醒是由别的进程或操作系统唤醒 不是自己唤醒自己
    • 被阻塞的进程需要的资源可被满足
    • 被阻塞的进程等待的事件到达
  • 进程结束 将进程所占用的资源还给操作系统
    • 正常退出
    • 错误退出
    • 致命错误(强制性的)
    • 被其他进程所杀(强制性的)
三状态进程模型
  • 运行状态(Running)
    • 进程正在处理机上执行
  • 就绪状态(Ready)
    • 进程获得了除处理机之外的所需资源 得到处理机后可运行
  • 等待状态(又称阻塞状态 Blocked)
    • 进程正在等待某个事件 而暂停的状态
  • 创建状态(New)
    • 进程正在被创建 还没到就绪状态前的状态
  • 结束状态(Exit)
    • 进程正在从系统中消失时的状态 系统正在回收它所占用的资源

process_state

进程切换
1
2
3
4
5
进程 1 执行 sleep() 进入 内核 内核调用函数设置定时器
进行调度 保存现场(到 PCB 中) 切换到 进程 2
进程 2 开始执行 若此时定时器时间到了 定时器产生 中断
中断服务例程 让 进程 2 暂停下来 并保护 进程 2 的现场 恢复 进程 1 的现场
让 进程 1 继续执行 进程 1 执行结束 再回到 操作系统

process_switching

进程挂起

处在挂起状态的进程映像在磁盘上 目的是减少进程占用内存

  • 等待挂起状态(Blocked-suspend)
    • 进程在外存并等待某事件的出现
  • 就绪挂起状态(Ready-suspend)
    • 进程在外存 但只要进入内存 即可运行 (内存空间不够或它的优先级不够高)
  • 挂起(Suspend) 把一个进程从内存转到外存
    • 等待 到 等待挂起 (没有进程处于就绪状态 或 就绪状态进程要求更多的内存)
    • 就绪 到 就绪挂起 (当有高优先级等待进程和低优先级就绪进程 总之就是 系统会认为高优先级的等待进程会很快就绪 就把低优先级的就绪进程换下 使得 高优先级的等待进程被激活后有足够的内存)
    • 运行 到 就绪挂起 (对抢先式分时系统 当有高优先级等待挂起进程因事件出现而进入就绪状态 而当前没有足够内存空间 它就会把当前正在运行的这个进程变成就绪挂起状态)
  • 激活(Activate) 把一个进程从外存转到内存
    • 就绪挂起 到 就绪 (没有就绪队列 或 挂起就绪队列进程优先级高于就绪进程)
    • 等待挂起 到 等待 (当一个进释放足够内存 并有 高优先级等待挂起进程)

process_suspend

状态队列

由操作系统来维护一组队列 表示系统中所有进程的当前状态

  • 不同队列表示不同状态
  • 根据进程状态不同 进程PCB 加入相应队列

process_state_queue

线程(Thread)

线程是进程的一部分 描述指令流执行状态 是进程中的指令执行最小单元 是 CPU 调度的基本单位

线程与进程的关系

线程 = 进程 - 共享资源 = 执行流

  • 线程的优点
    • 一个进程中可以有多个线程
    • 各个线程之间可并发执行
    • 各个线程之间可以共享地址空间和文件等资源
  • 线程的缺点
    • 一个线程崩溃 会导致其所属进程的所有线程崩溃

process_thread_relationship

线程与进程的区别

  • 进程是资源分配单位 线程是CPU调度单位
  • 进程拥有一个完整的资源平台 而线程只独享指令流执行的必要资源 (寄存器 栈)
  • 线程具有 就绪 等待 运行 三种基本状态和状态间的状态转换
  • 线程能减少 并发执行的时间 和 空间开销
    • 线程的创建和结束时间 比 进程 短 且 同一进程内的线程切换时间比进程短
    • 同一进程的 各线程间共享内存 和 文件资源 可 不通过 内核 进行 直接通信(省执行时间)

线程实现的三种方式

  • 用户线程(在用户空间实现)
  • 内核线程(在内核中实现)
  • 轻权进程(LightWeight Process 在内核中实现 支持用户线程 结合了用户线程和内核线程的优点)

用户线程

由一组用户级的线程库函数来完成线程的管理 包括线程的创建 终止 同步 调度等

1
2
3
4
操作系统内核里 仍然只有 PCB 来描述处理机调度的情况
操作系统并不感知用户态有多线程的支持
多线程的支持是用户的函数库支持的多线程
在应用程序内部构造 线程控制块(TCB) 来控制多个线程的交替和同步

user_thread

用户线程的特征

不依赖于操作系统内核

  • 内核不了解用户线程的存在
  • 可用于不支持线程的多进程操作系统

在用户空间实现的线程机制

  • 每个进程有私有的线程控制块(TCB) 列表
  • TCB 由线程库函数维护

同一进程内的用户线程切换速度快

  • 无需内核态 用户态的切换

允许每个进程拥有自己的线程调度算法

用户线程的不足
  • 线程发起系统调用而阻塞时 则整个进程进入等待
  • 不支持基于线程的处理机抢占(除非当前运行线程主动放弃 它所在进程的其他线程无法抢占CPU)
  • 线程只能按进程分配 CPU时间(多个线程的进程中 每个线程的时间片少)

内核线程

由内核通过系统调用实现的线程机制 由内核完成线程的创建 终止 管理

kernel_thread

内核线程的特征
  • 由内核来维护 PCB 和 TCB
  • 线程执行系统调用而被阻塞 不影响 其他线程
  • 线程的创建 终止 切换 开销大(因为要通过系统调用在内核中走一趟)
  • 以线程为单位进行 CPU时间分配(多线程的进程可获得更多的CPU时间)

轻权进程(LightWeight Process)

内核支持的用户线程 一个进程可有一个或多个轻量级进程 每个轻权
进程由一个单独的内核线程来支持

lightWeight_process

1
2
3
4
5
永久绑定线程 可看作是 内核支持的线程
未绑定的轻权进程 可由用户态来给出一些策略 提高应用的效率
未绑定的轻权进程 就像用户线程实现的多线程 可以自己决定调度算法之类的
但同时 永久绑定线程 又是 内核原生就支持的线程 所以轻权进程 是融合了 内核线程和用户线程的优点
实际上轻权进程 优点没有体现出来 因此没被广泛使用

内核线程和用户线程和轻权进程的对应关系

thread_relationship

1
2
3
4
一对一 可看作是 多进程多线程操作系统
多对一 可看作是 多进程单线程操作系统(用户态实现多线程)
多对多 轻权进程
实际上最广泛使用 一对一 多进程多线程操作系统