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