线程/进程

72 阅读6分钟

一.线程是什么

线程 = 一组用于“让 CPU 能从上次停下的地方继续执行”的运行时状态集合。

线程是执行所需状态的载体

线程本身不执行代码,
Core 执行代码;
线程只是告诉 Core:
“我上次跑到这里了,你接着从这儿跑。”


二.线程是由什么组成的


image.png

✅ 1️⃣ 寄存器上下文(Register Context)——最核心

这是线程“能继续跑”的根本。

至少包括:

  • PC / RIP:程序计数器(下一条要执行的指令)

  • SP / RSP:栈指针

  • 通用寄存器(保存中间计算结果)

  • 标志寄存器(条件码等)

没有寄存器上下文,线程就不知道自己跑到哪了

📌 上下文切换的本质
就是保存当前线程的寄存器 + 恢复另一个线程的寄存器。


✅ 2️⃣ 栈(Stack)——执行历史与调用现场

每个线程必须有自己的栈

栈里通常存着:

  • 函数调用链(return address)

  • 局部变量

  • 保存的寄存器值(callee-saved)

  • 异常处理信息等

多线程共享代码、共享堆,
但绝对不能共享栈

📌 这也是为什么:

  • 同一个函数

  • 在两个线程里

  • 可以同时运行而不互相覆盖局部变量


✅ 3️⃣ 线程控制块(TCB / task_struct)——OS 视角的线程本体

这是内核用来管理线程的数据结构

里面通常包含:

  • 线程 ID

  • 当前状态(running / runnable / blocked)

  • 调度信息(优先级、时间片)

  • 所属进程

  • 栈指针、寄存器保存区指针

  • CPU 亲和性信息

  • 信号、调度统计信息等

这是调度器“认识线程”的唯一方式。


✅ 4️⃣ 所属进程的资源视图(Shared Context)

线程不拥有完整资源,而是共享进程的:

  • 虚拟地址空间

  • 堆(heap)

  • 全局变量

  • 文件描述符

  • 信号处理设置(大多)

所以你可以这样理解:

进程 = 资源容器
线程 = 执行容器


把这些拼起来,一张“真实结构图”(文字版)

线程
├── 寄存器上下文(能不能继续执行)
├── 私有栈(执行路径)
├── 线程控制块 TCB(调度与管理)
└── 共享进程资源
     ├── 地址空间
     ├── 堆
     ├── 全局变量
     └── 文件描述符

三.线程的作用

  1. 实现并发执行​ 在一个进程内开启多个线程,可以让多个任务看似“同时”推进,提高 CPU 利用率,尤其是当一个线程因 I/O 等待而停顿时,其他线程可以继续运行。
  2. 减少上下文切换成本(相对进程) ​ 因为线程共享进程的地址空间和资源,切换时只需保存/恢复寄存器上下文和栈,不必切换页表等内核结构,所以比进程切换快得多。
  3. 简化数据共享与通信​ 同一进程的线程天然共享堆、全局变量、文件描述符等,数据传递无需额外的 IPC 机制(但也需注意同步问题,如竞态条件)。
  4. 充分利用多核 CPU​ 内核级线程可由操作系统调度到不同核心并行执行,实现真正的硬件并行,提高吞吐量。

四、进程是什么

进程 = 程序的一次执行实例 + 它拥有的资源集合 + 至少一个执行流(线程)。

从操作系统视角看:

  • 进程是资源分配的基本单位(内存、文件、信号处理权等分配给进程)
  • 进程是独立地址空间的保护边界(一个进程崩溃通常不会直接影响另一个进程)
  • 现代操作系统中,进程至少包含一个线程(Linux 2.x 里甚至用轻量级进程来模拟线程),线程才是 CPU 调度的基本单位。

换句话说: 进程 = 资源 + 状态 + 至少一个执行流(线程) ​ 没有线程的进程只是一个静态的资源壳,无法执行代码。


五、进程的组成

1. 操作系统管理视角:进程控制块(PCB)、程序段、数据段

  • PCB在 Linux 中是 task_struct,相当于“进程的身份证和档案”

  • 内容包括:

    • 进程标识(PID、PPID、TGID)
    • 进程状态(运行、睡眠、僵尸等)
    • 调度信息(优先级、策略)
    • 内存管理指针(mm_struct
    • 文件描述符表(files_struct
    • 信号处理结构
    • 资源限制(rlimit
    • 上下文指针(指向寄存器备份、内核栈等)
  • 程序段

    程序段是进程的一部分,包含了程序的代码,即指令序列。程序段是静态的,存放在磁盘上的可执行文件中。

  • 数据段

    数据段是进程在运行过程中产生的各种数据,包括程序中定义的变量等。数据段也是静态的,反映了进程在某一时刻的状态。

2. 程序运行内存视角:进程地址空间布局

从高地址到低地址一般包括:

  • 内核空间:所有进程共享,只有内核态能访问
  • 栈(Stack) :每个线程独有,向下增长,存局部变量、调用链
  • 内存映射段:动态库、mmap 文件
  • 堆(Heap) :动态分配内存,向上增长
  • BSS 段:未初始化的全局/静态变量(加载时清零)
  • 数据段(.data) :已初始化的全局/静态变量
  • 文本段(.text) :程序代码(只读)

3. 进程的资源集合

  • 虚拟地址空间:代码、数据、堆、栈、共享库的映射
  • 文件描述符表:打开的文件、socket、管道等
  • 信号处理设置:如何响应异步事件
  • 工作目录、根目录等文件系统信息
  • 线程集合:至少一个主线程,可创建更多线程

六、进程的作用

  1. 资源隔离与保护​ 每个进程有独立的虚拟地址空间,一个进程的错误(如空指针解引用)不会影响其他进程,提高了系统的稳定性和安全性。
  2. 资源管理的基本单位​ 操作系统以进程为单位分配内存、文件句柄、网络端口等资源,进程间资源互不干扰。
  3. 提供执行环境​ 进程为代码执行提供完整的上下文:地址空间、文件、信号处理等,使程序能独立于其他程序运行。
  4. 支持并发与多任务​ 多进程可以在宏观上同时运行(在多核 CPU 上可真正并行),实现多任务操作系统的基础。
  5. 简化错误恢复​ 一个进程崩溃可以被操作系统回收,不影响整个系统或其他进程的运行(守护进程、服务常采用多进程架构)。

七、线程与进程的关系总结(结构化)

维度进程(Process)线程(Thread)
本质资源 + 至少一个执行流的容器执行流的载体(寄存器+栈+TCB)
资源拥有独立地址空间、文件描述符等共享进程资源
切换成本高(切换页表、刷新 TLB 等)低(仅寄存器、栈)
调度单位现代 OS 中调度的基本单位是线程直接被调度器调度
隔离性强(一个进程崩溃不影响别的进程)弱(线程崩溃可能导致整个进程终止)
通信方式IPC(管道、消息队列、共享内存等)直接读写共享变量(需同步)
创建开销大(分配资源、建立地址空间)小(共享资源,仅分配栈和 TCB)