4.8 KiB
4.8 KiB
程序、进程与线程
程序
定义
程序是存储在硬盘的一组指令集和,它是对计算任务的完整描述,是一个被动实体。类似于一本菜谱,记录了完整的烹饪步骤。
核心特征
| 属性 | 说明 |
|---|---|
| 静态性 | 程序是一个文件(如 .exe、.go),不占用 CPU 或内存执行资源 |
| 持久性 | 可长期存在于存储介质上 |
| 无生命周期 | 没有创建、运行、消亡的状态变迁 |
进程
定义
进程是程序的一次动态执行过程,是操作系统进行资源分配的基本单位。它就像按照菜谱进行烹饪的过程,需要占用资源,有始有终。它由以下三部分构成。
| 组成部分 | 作用 |
|---|---|
| 程序段 | 描述进程要完成的功能,是控制进程执行的指令集 |
| 数据段 | 程序执行时所需的数据和工作区(全局变量、堆等) |
| 进程控制块(PCB) | 包含进程的描述信息和控制信息,是进程存在的唯一标志 |
核心特征
- 动态性:进程有生命周期(创建 → 就绪 → 运行 → 阻塞 → 终止)
- 独立性:每个进程拥有独立的地址空间(虚拟内存空间、代码、数据、系统资源的集合)
- 并发性:多个进程可在宏观上同时运行
- 资源拥有者:进程拥有独立的文件描述符、环境变量、用户ID等资源
线程
定义
线程是CPU进行运算调度的最小单位,是进程中的一条执行路径,一个进程至少有一个线程(也就是主线程)。它就像多位厨师共用厨房的资源(水、灶台、食材等),但是每人也都有自己的独有的刀具、围裙等,他们需要协调使用厨房做菜。
核心特征
线程虽然共享进程的资源,但每个线程拥有自己的私有数据:
| 独有内容 | 说明 |
|---|---|
| 线程 ID | 唯一标识 |
| 寄存器状态 | 包括程序计数器(PC)和栈指针 |
| 栈 | 独立运行栈,用于函数调用和局部变量 |
| 信号掩码 | 线程级别的信号处理设置 |
| 优先级 | 调度优先级 |
| 线程专用存储(TLS) | 线程私有的全局变量 |
用户态与内核态
内核态
运行操作系统内核代码,拥有对硬件的完全控制权,负责管理内存、进程、文件系统、网络等底层资源。
用户态
运行用户应用程序,无法直接访问硬件或内核数据结构,必须通过 系统调用(System Call)请求内核代为执行特权操作。
切换过程
为了保护系统安全与稳定,操作系统会对CPU的执行权限进行分级,不同的CPU架构有不同的等级,但是通常都遵循应用在最低特权级(用户态)运行,内核在次高特权级(内核态)运行,通过CPU硬件强制隔离特权操作。当在X86架构的CPU运行时,一个应用程序需要执行特权操作(比如读写文件),过程大致是这样的:
- 触发
程序调用
read()等库函数,最终执行 CPU 的syscall指令。这条指令告诉 CPU:“我要切换到内核态干正事”。 - CPU 硬件自动切换
CPU 在硬件层面做三件关键事:
- 把特权级从 Ring 3(用户态) 切换为 Ring 0(内核态)。
- 将栈指针从用户栈切换到内核栈(从 MSR 中读取预设的内核栈指针)。
- 把返回地址(下一条指令)和标志寄存器保存到特定寄存器(如
rcx、r11),然后跳转到内核预先设置好的入口函数。
- 内核软处理
入口函数将刚才没来得及保存的全部寄存器压入内核栈(形成
pt_regs结构),然后根据系统调用号(放在rax通用寄存器中)从系统调用表里找到对应的内核函数(如ksys_read)并执行。 - 内核执行 & 返回
内核函数完成实际工作(检查权限、读取数据等),把结果放在
rax通用寄存器中。返回前,内核检查是否有其他任务需要处理(如信号、调度),然后通过sysret指令恢复之前保存的寄存器、用户栈和返回地址,特权级自动切回 Ring 3,程序从当初的下一条指令继续运行。