理解 Linux 中的线程
多个 PCB 可对应同一个地址空间。线程是进程的执行流,执行粒度比进程更细。
传统进程模型通常指单线程,即主线程。操作系统以进程为单位分配资源,但进程内部只有一个执行流。

实际上,多个线程加上地址空间、页表及部分物理内存才构成进程。
CPU 无法区分主线程与其他线程,它只识别执行流。在 Linux 中,执行流被称为轻量级进程,即线程。
重新定义线程与进程
线程:操作系统调度的基本单位。 进程:操作系统分配资源的基本实体,线程是进程内部的执行流资源。
重谈地址空间
页表结构

CPU 中 CR3 寄存器存储页表地址,访问的是虚拟地址。虚拟地址到物理地址的转换过程如下:
以 32 位电脑为例,共有 2^32 个地址。页表项包含虚拟地址、物理内存及权限位。由于物理内存限制,并非一一对应关系。
假设物理内存 4GB,一个页框 4KB,共有 2^20 个页框。页表 32 位被拆分为 10+10+12:前 10 位对应第一级页表(页目录),中间 10 位对应第二级页表,后 12 位为页框偏移。第一级页表指向第二级页表,第二级页表存储物理页框号。
注意:
- 第二级页表通常填不满,因为操作系统不会用完所有物理内存。
- 虚拟地址后 12 位不存储在页表中,CPU 可直接提取低 12 位作为偏移量。
页表大小计算: 每个页目录项指向第二级页表加标识位,占 4 字节。1024 * 4 = 4KB。 同理,第二级页表项也是 4KB。 整个页表系统 = 1 个页目录 + N 个第二级页表 (4KB) + (N × 4KB)。 最多约 4MB,实际使用更少。
一个第二级页表可映射 1024 * 4KB = 4MB 虚拟内存。 创建进程涉及复杂的页表管理,开销较大。

此外,C/C++ 中变量取地址得到的是起始内存地址,例如 int 类型占 4 字节,地址计算为起始地址加偏移量。

线程与进程切换
线程比进程轻量化的原因:
- 创建和释放更轻量:线程只需共享地址空间和页表等资源,仅需分配栈空间。
- 切换更轻量:CPU 缓存(Cache)会保存上下文热数据。切换进程时 Cache 失效冷却,而线程属于同一地址空间,Cache 命中率更高。
线程分配空间的本质是分配地址空间。


