操作系统笔记 (1) —— 进程和线程

进程 (Process)

定义

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

组成

一个进程包括了正在运行的一个程序的所有状态信息:

  • 程序的代码
  • 程序处理的数据
  • 程序计数器中的值,指示下一条将运行的指令
  • 一组通用的寄存器的当前值、堆和栈等
  • 一组系统资源,如打开的文件等

特点

  • 动态性:可动态地创建、切换、结束进程
  • 并发行:进程可以被独立调度并占用处理运行(并发:某个时间段;并行:某个时刻)
  • 独立性:不同进程的工作(正确性)不相互影响
  • 制约性:因访问共享数据/资源或进程间同步而产生制约

进程和程序

联系

  • 程序是产生进程的基础
  • 程序的每次运行构成不同的进程
  • 进程是程序功能的体现
  • 通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序

区别

  • 进程是程序的执行(动态的);程序是有序代码的集合(静态的)
  • 进程有核心态/用户态
  • 进程是一个状态变化的过程(暂时的);程序可以长久保存(永久的)
  • 进程与程序的组成不同:进程的组成包括程序、数据和进程控制块(即进程状态信息)

进程的生命期管理

创建

引起进程创建的 3 个事件:

  • 系统初始化
  • 用户请求创建一个新进程
  • 正在运行的进程执行了创建进程的系统调用

运行

内核选择一个就绪的进程,让它占用处理及并执行。

等待(阻塞)

以下情况进程等待:

  • 请求并等待系统服务,无法马上完成
  • 启动某种操作,无法马上完成
  • 需要的数据没有到达

进程只能自己阻塞自己。

唤醒

唤醒进程的原因:

  • 被阻塞进程需要的资源可被满足
  • 被阻塞进程等待的事件到达
  • 将该进程的 PCB 插入就绪队列

进程只能被别的进程或 OS 唤醒。

结束

以下情况进程结束:

  • 正常退出(自愿)
  • 错误退出(自愿)
  • 致命错误(强制)
  • 被其他进程所杀(强制)

进程状态变化模型

进程状态转换

三种基本状态

  • 运行 (Running):当一个进程正在处理机上运行时
  • 就绪 (Ready):一个进程获得了除处理机之外的一切所需资源,一旦得到处理机即可运行
  • 等待/阻塞 (Blocked):一个进程正在等待某一事件而暂停运行,如等待某资源、输入/输出完成

其他状态

  • 创建 (New):一个进程正在被创建,还没被转到就绪状态之前的状态
  • 结束 (Exit):一个进程正在从系统中消失时的状态,由于进程结束或其他原因所致
  • 挂起 (Suspend):把一个进程从内存转到外存。挂起状态时,进程没有占用内存空间,处在挂起状态的进程映像在磁盘上

进程挂起

  • 阻塞挂起 (Blocked suspend):进程在外存并等待某事件的出现
  • 就绪挂起 (Ready suspend):进程在外存,但只要进入内存,即可运行
  • 与挂起相关的状态转换
    • 阻塞 => 阻塞挂起:没有进程处于就绪状态或就绪进程要求更多内存资源时,进行此种转换,以提交新进程或运行就绪进程
    • 就绪 => 就绪挂起:当有高优先级阻塞进程和低优先级就绪进程时,OS 选择挂起低优先级就绪进程
    • 运行 => 就绪挂起:对抢先式分时系统,当有高优先级阻塞挂起进程因事件出现而进入就绪挂起,OS 可能把运行进程转到就绪挂起状态
    • 就绪挂起 => 就绪:没有就绪进程或挂起就绪进程优先级高于就绪进程时,进行此种转换
    • 阻塞挂起 => 阻塞:当一个进程释放足够内存时,OS 会把一个高优先级阻塞挂起进程转换为阻塞进程
  • 在外存时的状态转换
    • 阻塞挂起 => 就绪挂起:当有阻塞挂起进程因相关事件出现时,OS 会把阻塞挂起进程转换为就绪挂起进程
  • 状态队列
    • 由 OS 维护一组队列,表示系统中所有进程的当前状态
    • 不同的状态分别用不同的队列来表示(就绪队列、各类阻塞队列等)
    • 每个进程的 PCB 都根据它的状态加入到相应的队列中,当一个进程状态发生变化时,它的 PCB 从一个状态队列中脱离出来,加入到另一个队列

线程 (Thread)

定义

进程当中的一条执行流程,即

\[ \text{线程} = \text{进程} - \text{共享资源} \]

  • 属于同一个进程的多个线程共享进程的所拥有的资源(代码、数据、打开的文件等)
  • 线程有独立的线程控制块 (TCB),包括程序计数器 (PC)、堆栈 (SP)、State、寄存器 (Registers) 等
  • 优点:
    • 一个进程可以同时存在多个线程
    • 各个线程之间可以并发地执行
    • 各个线程之间可以共享地址空间和文件等资源
  • 缺点:一个线程崩溃,会导致其所属进程的所有线程崩溃

线程的实现

  • 用户线程:在用户空间实现的线程机制(OS 看不到,由用户线程库管理)
    • 不依赖 OS 的内核,由一组用户级的线程库函数完成线程的管理,包括创建、终止、同步和调度等
    • 可用于不支持线程技术的多进程 OS
    • 每个进程都需要自己私有的 TCB 列表,用于跟踪记录其各个线程的状态(PC、栈指针、寄存器等),TCB 由线程库函数来维护
    • 用户线程的切换也是由线程库函数来完成,无需用户态/核心态切换,速度快
    • 允许每个进程拥有自定义的线程调度算法
    • 缺点:如果一个线程发起系统调用而阻塞,则整个进程在等待;一个线程开始运行后,除非主动交出 CPU 使用权,否则其所在进程中的其他线程无法运行;在多线程执行时,每个线程分到的时间片较少,执行较慢
  • 内核线程:在 OS 内核中实现的线程机制,由 OS 内核来完成线程的创建、终止和管理
    • 在支持内核线程的 OS 中,由内核维护进程和线程的上下文信息(PCB 和 TCB)
    • 线程的创建、终止和切换都是通过系统调用/内核函数(用户态 => 内核态)的方式进行,由内核完成,系统开销大
    • 在一个进程中,如果某个内核线程发起系统调用而被阻塞,并不会影响其他内核线程的运行
    • 时间片分配给线程,多线程的进程获得更多 CPU 时间
  • 轻量级进程:在内核中实现,支持用户线程
    • 内核支持的用户线程,一个进程可有一个或多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持

进程与线程的比较

  • 进程是资源分配单位;线程是 CPU 调度单位
  • 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和堆栈
  • 线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换关系
  • 线程能减少并发执行的时间和空间开销:线程的创建、终止时间比进程短;同一进程内线程切换时间比进程短(无需切换页表);同一进程的各线程可直接进行不通过内核的通信