85 lines
4.8 KiB
Markdown
85 lines
4.8 KiB
Markdown
|
||
|
||
## 程序、进程与线程
|
||
|
||
### 程序
|
||
|
||
#### 定义
|
||
|
||
程序是存储在硬盘的一组指令集和,它是对计算任务的完整描述,是一个被动实体。类似于一本菜谱,记录了完整的烹饪步骤。
|
||
|
||
#### 核心特征
|
||
|
||
| 属性 | 说明 |
|
||
| :------------- | :-------------------------------------------------------- |
|
||
| **静态性** | 程序是一个文件(如 .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**,程序从当初的下一条指令继续运行。
|
||
|