039 线程概念

线程概念

1. 什么是线程?它和进程的关系?

1. 粒度:执行的“颗粒大小”

粒度(Granularity) 是个比喻术语,表示一个单位在调度或执行上的“精细程度”。举例说明:

  • 进程 是一个较大单位(粗粒度):拥有独立地址空间、资源。

  • 线程 是进程内部的小单位(细粒度):共享地址空间,调度更轻便。

  • 比喻一下:一个公司(进程)可能有多个部门(线程),每个部门是公司内部的执行单位,共享同一个资源(办公室、资金)。

线程执行进程的代码(粒度细)

  • 多线程可以同时执行同一个进程的多个代码分支,这比进程切换效率高。
  • 一个进程内部多个线程共同完成任务,就像车间里多个工人一起干活。

2. 线程的定义

线程是操作系统调度的最小执行单位。

  • 在用户/开发者角度看:线程是进程中的“执行分支”,多个线程可以并发执行进程中的不同任务。

  • 在内核角度看:内核调度的是线程(Linux 称为“轻量级进程”),不是传统意义上的进程。

  • CPU 视角:只有“执行流”,每个 task_struct(无论是进程还是线程)在 CPU 看来都是“可调度实体”。因此 Linux 把线程干脆叫“轻量级进程”——名字里仍带“进程”,只是资源复用程度不同。

执行流 = CPU 上能被调度运行的最小单位,无论是:主线程执行 main()、子线程处理任务、内核线程处理 I/O、甚至信号处理函数上下文切换,本质上,它们都是“一个在 CPU 上执行的流动单元”。所以我们抽象地称它为 执行流


CPU 只调度执行流(线程):CPU 的调度单位是线程(执行流),不是进程。所以:CPU 只管“谁来执行”,而不是“哪个进程”执行。

3. Linux 中线程的实现方式?

PCB 结构理解(进程是资源实体):进程 = PCB(Process Control Block) + 代码/数据

  • PCB 记录了进程的所有管理信息(PID、状态、内存映射、文件表等)。
  • 线程依附进程执行,不拥有自己的完整 PCB,只在进程的 PCB 中挂靠自己的线程控制块。

Linux 并没有原生的“线程”这个独立结构,而是通过内核的 进程机制(task_struct) 来实现线程,无论是普通进程、还是线程,在内核中都是 task_struct 实例。在 Linux 中,线程就是一种特殊的“进程”,又叫 轻量级进程(Lightweight Process,LWP)。多个线程共享同一个进程的资源(代码段、数据段、堆、文件描述符等),但有自己独立的:

  • 栈空间(私有栈)
  • 寄存器现场(上下文)
  • 线程 ID(TID)

[!NOTE]

那这样做的好处(优雅性)是什么?

这正是 Linux/OS 设计哲学的体现:

  • 统一的数据结构,简化调度系统。
  • 灵活的共享机制。
  • 复用代码(内核的数据结构),降低 bug 的可能性和维护难度。

Windows 内核线程是“真正意义上的线程”:Windows 内核中有 线程控制块,叫做 TCB(struct TCB,Thread Control Block)。它是 Windows 原生线程结构,用于记录线程上下文、栈地址、状态等,是 Windows 的调度单位。Windows 中,进程是资源容器,线程是独立的执行单位,系统明确区分这两个概念。

4. 为什么线程要在进程“内部”执行?

  • 原因:线程不拥有自己的资源,必须依附进程的资源(如地址空间)才能执行。 任何执行流想跑起来都必须:有代码(指令)、有栈、有页表(地址空间)(加粗是必要条件!),全部条件还需要 task_struct(调度实体)、上下文。
  • 所以:“地址空间是进程的资源窗口”,线程就是进程内部的执行分支。线程“在进程地址空间内跑”不是可选,而是必选项;离了地址空间,CPU 连下一条指令在哪都不知道。

image-20250720155626624

5. 进程 vs 线程

【os 浅尝】话说进程和线程~ | B 站
进程和线程的区别 | B 站
【操作系统】进程和线程的区别 | B 站
线程、进程和应用程序的关系和原理(干货教程) | B 站

对比点进程线程
是否独立独立,拥有自己的地址空间、页表依附于进程,共享进程地址空间
是否拥有资源是,拥有文件描述符、内存等否,只拥有少量运行所需资源
调度粒度粗(整个进程调度)细(线程调度)
创建/销毁开销大(复制页表、资源)小(切换栈、寄存器)
通信效率低(需进程间通信 IPC)高(共享内存)
健壮性进程崩溃不影响其他进程线程崩溃导致整个进程崩溃

image-20250720160747631

2. 页表

页式存储管理讲解 | B 站

「Coding Master」第 30 话 这个内存分页,就挺难的 | B 站

CPU 眼里的:二级页表 | MMU | 虚拟内存 | B 站

一步一图带你构建 Linux 页表体系 —— 详解虚拟内存如何与物理内存进行映射 | 博客园

1. 什么是页表(Page Table)?

1. 本质

页表是操作系统用来 管理虚拟地址与物理地址映射关系 的数据结构。每个进程都有自己的 虚拟地址空间 ,而页表就是这个地址空间的“地图”,告诉 CPU 如何将一个虚拟地址转换为物理地址。简单说:我们访问的是虚拟地址,系统通过页表找出对应的物理地址。

2. 页表的核心单位

名称含义单位特点举例
页面(Page)虚拟地址空间被划分为固定大小的块通常为 4KB虚拟地址的基本单位每个页面对应一个物理页框
页框 / 页帧(Page Frame)物理内存被划分为固定大小的块通常为 4KB存放页面数据的物理单元物理内存中的 4KB 单元
页目录项(PDE)一级页表项,指向页表4 字节(32 位)页目录有 1024 项PDE [i] → 页表起始地址
页表项(PTE)二级页表项,指向页框4 字节(32 位)PTE [i] → 页框起始地址用于虚拟地址到物理地址映射
页内偏移(Offset)页内地址偏移量12 位(0~4095)用于在页框中定位具体字节偏移量 + 页框地址 = 物理地址

image-20250720151706339

image-20250720152800793

3. 为什么需要页表?

页表是实现虚拟内存机制的基础,二级页表是为了节省内存并提高效率,多级页表则是为了支持更大的地址空间和更灵活的管理方式。

为什么需要二级页表?

单级页表的问题(以 32 位系统为例):32 位系统地址空间为 4GB(2^32),页大小为 4KB(2^12),总共需要 2^20 = 1,048,576 个页表项,每个页表项 4 字节,总大小为 4MB。所以:页表大小 = 2²⁰ × 4B = 4MB,每个进程都要维护一张 4MB 的页表(即使它只用了一点虚拟内存),这对于上了年代的机器来说是灾难性设计!

就是因为占内存大、浪费严重、不支持“按需分配”所以诞生了二级页表,二级页表是对“空间换时间”的优化倒转 —— 用时间(多查一次)换空间(只分配用到的),再到后来的多级页表:节省空间、支持按需映射、提升效率。

4. 32 位系统中二级页表的工作原理结构图

image-20250720153638765

1. 分解说明
  • 虚拟地址 = 32 位: 虚拟地址由 3 部分组成:

    1
    2
    [10位 页目录索引] [10位 页表索引] [12位 页内偏移]
    (2^10 条) (2^10 条) (4KB 页面)
  • 页大小 = 4KB = 2¹²: 最后 12 位表示页内偏移(Offset)

  • 页表项大小 = 4 字节(32bit): 一个页表(4KB)能容纳:4KB ÷ 4B = 1024 条项,刚好对应 2¹⁰。

2. x86 32 = 10+10+12 的意义

虚拟地址 32 位 = 10(页目录)+ 10(页表)+ 12(偏移)

位数说明
页目录10一级表,存放 页表的指针,选择哪个页表(共 1024 个)
页表10二级表,存放 页 → 物理帧 映射,选择哪个页表项
偏移12不变,表示页中具体偏移地址(4KB 页大小)

image-20250720154605759

3. 再谈线程

1. 线程的优点(相对进程)

编号优点描述解释说明或场景举例
1创建开销小新线程共享父进程资源,不需要重新分配地址空间等
2上下文切换代价小线程切换只需切换少量寄存器,进程切换需切页表等
3占用资源少共享代码段、数据段、堆等,减少内存资源开销
4支持并发执行多线程可利用多核 CPU,提高执行效率
5提升 IO 密集程序性能下载、读写磁盘等可异步等待,主线程可继续执行
6提升计算密集程序性能(多核)可将任务拆分成多个子任务,多个核并行执行
7IO 操作可并发等待,提高吞吐多线程各自等待不同 IO 资源,实现重叠与效率提升

2. 线程的缺点

编号缺点描述举例或解释
1同步/调度带来性能损失多个计算密集型线程争抢 CPU,带来线程调度/同步开销
2健壮性降低不小心共享了不该共享的变量,或同步出错易出 bug
3缺乏访问隔离保护所有线程共享进程资源,某线程异常可能影响整个进程
4编程难度高多线程程序调试困难,如死锁、竞态条件难定位

3. 线程异常处理风险(容易忽略)

问题描述说明
崩溃传染性强一个线程崩溃(如除 0、野指针),触发信号机制,整个进程被终止
同步问题锁没加好、条件变量判断失误,可能引发死锁、数据污染等不可预测问题
资源泄漏某线程提前崩溃未释放资源,整个进程泄漏,所有线程随之退出

4. 线程适用场景(牢记)

场景类型描述示例
CPU 密集型多核计算视频渲染、图片处理、机器学习模型训练、加密解密
IO 密集型高并发 IO网络爬虫、数据库操作、磁盘文件下载、日志写入
用户体验优化前后台并行处理一边写代码一边下载依赖,一边加载图片一边展示 UI

5. 记忆口诀

  • 线程优点快轻小,共享资源效率高;
  • 线程缺点易崩溃,调试困难需谨慎;
  • CPU 并行靠分工,IO 并发靠等待;
  • 善用线程提性能,滥用线程埋雷坑。

线程相较于进程最大的优势是开销小、切换快、共享资源,适合高并发或高性能场景。比如在多核处理器中跑 CPU 密集任务,或者处理大量 IO 等待时都能有效提升效率。但线程也存在缺乏隔离、同步复杂、异常传播等风险,因此使用时需要严格管理共享资源和同步机制。