Linux 进程与线程完整区分

一、底层本质(最核心)

Linux 内核只有一种调度对象:task_struct(任务)。

  1. 进程:一个独立 task_struct,拥有一套完整、独占的系统资源。
  2. 线程(LWP 轻量级进程):一组多个 task_struct共享同一套资源,每个 task_struct 是独立调度单元。

创建底层都依赖 clone() 系统调用,区别只在传入的共享标记:

  • fork()clone(无共享标记) → 新独立进程
  • pthread_createclone(CLONE_VM | CLONE_FILES | CLONE_SIGHAND ...) → 同组线程

二、资源层面区别(最直观分水岭)

1. 虚拟地址空间 mm_struct

  • 进程:各自独立 mm,互不访问对方堆、代码段、全局变量;进程间读写对方内存必须用 IPC(管道、共享内存、socket)。
  • 同进程下所有线程:共用同一个 mm,线程之间直接读写全局变量、堆、静态变量,共享内存无额外开销。

2. 文件描述符表 files_struct

  • 进程:独立 fd 表,A 进程打开的文件、socket,B 进程看不到。
  • 线程:共享 fd 表,一个线程 open 打开文件,其余线程都能读写、关闭。

3. 信号处理 signal_struct / sighand_struct

  • 进程:独立信号处理函数、信号掩码。
  • 线程组共享信号处理函数;但每个线程私有阻塞信号集
  • 发给线程组的信号默认投递到任意一个线程;发给特定 LWP 的信号只影响单个线程。

4. 私有资源(线程独有,进程天然自带)

每个 task_struct 私有内容,不管进程还是线程都有:

  1. 内核栈 + 用户栈(线程栈默认 8MB)
  2. CPU 硬件上下文 thread_struct(寄存器、程序计数器)
  3. 自己的 pid(LWP ID)
  4. 线程私有局部变量、TLS 线程本地存储
  5. 调度状态、时间片、优先级

5. 标识 ID 区分

  • 进程:pid == tgid
  • 线程:组内所有线程 tgid 相同(等于主线程 pid),每个线程 pid 唯一命令 ps -L / top -H 能看到 LWP 线程 ID。

三、调度与并行

  1. 调度最小单位:线程(单个 task_struct)内核调度器不区分进程、线程,只看 task_struct。
  2. 多核并行:
    • 多进程:每个进程的 task_struct 可分发不同 CPU 核心,支持并行;进程切换代价极高。
    • 多线程:同组多个 task_struct 可分到多核同时运行,真正并行;切换代价远低于进程。
  3. 阻塞行为:
    • 一个线程 read/recv 阻塞:仅当前 task_struct 休眠,同进程其他线程正常调度运行。
    • 一个进程阻塞:仅自身休眠,不影响其他进程。

四、创建、销毁、切换开销对比

1. 创建开销

  • 进程:极高。需要拷贝完整页表、地址空间、文件、信号资源,大量内存复制。
  • 线程:极低。仅新建独立栈和 task_struct,资源全部共享,几乎无拷贝。

2. 上下文切换开销(CPU 切换执行流)

  1. 进程切换:必须替换 mm,刷新 TLB、缓存、页表,CPU 缓存大面积失效,开销巨大。
  2. 线程切换:共享同一份地址空间,不需要切换页表、刷新 TLB;只保存 / 恢复寄存器,开销很小。

3. 退出影响

  • 主线程退出:默认整个进程所有线程一同销毁;
  • 任意子线程单独退出:仅销毁自身 task_struct,不影响同组其他线程;
  • 进程退出:所有关联 task_struct 全部销毁,释放全部资源。

五、通信方式差异

  1. 进程间通信 IPC(成本高):管道、FIFO、消息队列、共享内存、信号量、socket;必须内核介入传递数据。
  2. 线程间通信(成本极低):直接读写全局变量,配合互斥锁、条件变量;内存天然共享。

六、优缺点与适用场景

多线程适用场景(IO 密集、计算密集)

  • 优点:创建 / 切换快、内存共享、多核并行、资源利用率高
  • 缺点:共享内存带来竞态问题,必须加锁;一个线程异常崩溃会带走整个进程所有线程

多进程适用场景(高隔离服务,如 Nginx、PHP-FPM)

  • 优点:资源完全隔离,单个进程崩溃不会影响其他进程;数据互不干扰,安全性高
  • 缺点:创建、切换成本高;数据交互只能靠笨重 IPC

极简对比表格

维度 进程 线程(LWP)
内核结构 独立 task_struct,独占 mm 同组多个 task_struct,共享 mm
地址空间 完全独立 全部共享
创建开销 大,复制全部资源 小,仅新建栈
切换开销 极大,刷新页表 TLB 很小,无需切换地址空间
通信方式 IPC,内核中转 直接共享内存,加锁即可
崩溃影响 仅自身退出 单线程崩溃 → 整个进程退出
ID pid=tgid tgid 统一,pid 各自不同
调度单位 单个进程等价单线程 每个线程独立调度单元

一句话总结

进程是资源隔离容器,线程是容器内可独立调度的执行流;Linux 下线程就是共享了进程全套资源的轻量级 task_struct。

Windows 进程与线程区别,顺带和 Linux 做对比

一、底层模型核心差异(最关键)

Windows 采用 2 层内核对象模型,和 Linux 一套 task_struct 大一统完全不同:

  1. 进程(Process):内核对象,纯粹资源容器,本身不能被 CPU 调度,没有执行能力;
  2. 线程(Thread):内核对象,CPU 最小调度单位,依附进程存在,真正跑代码。

Windows 原生是 1:1 内核线程模型:用户层 CreateThread 直接创建内核线程,内核调度器直接管理每条线程。

内核数据结构

  • 进程:EPROCESS 结构体,存放虚拟内存、句柄表、权限、进程环境等所有资源;
  • 线程:ETHREAD 结构体,保存寄存器上下文、栈、调度状态、所属进程指针;每个 ETHREAD 内部有指针指向归属的 EPROCESS,一个 EPROCESS 可以挂多个 ETHREAD。

Linux 是反过来:只有 task_struct,靠是否共享 mm 区分进程 / 线程;Windows 是两套独立内核对象,天然分开。

二、资源归属对比(Windows 视角)

1. 虚拟内存空间

  • 进程:独占一套完整虚拟地址空间,每个进程有独立页目录;
  • 线程:同进程所有线程完全共享进程的地址空间,全局变量、堆、dll 代码段互通,无需 IPC。和 Linux 行为一致,但底层结构体分开管理。

2. 内核句柄表(文件、窗口、socket、互斥量等)

句柄表挂在 EPROCESS 上,同进程所有线程共享同一张句柄表:线程 A 打开文件得到句柄,线程 B 可直接使用、关闭。

3. 私有资源(每个线程独有)

  1. 用户栈 + 内核栈;
  2. CPU 寄存器上下文(线程切换只换这个);
  3. TLS 线程本地存储;
  4. 线程优先级、调度统计、阻塞状态;
  5. 异常上下文、异步 IO 上下文。

三、调度、并行、阻塞行为

  1. 最小调度单元:线程(ETHREAD),进程不参与调度;
  2. 多核并行:多线程 / 多进程都能分发到不同 CPU 核心并行执行;
  3. 阻塞特性:单个线程调用阻塞 API(ReadFile、Recv)只会挂起当前 ETHREAD,同进程其他线程正常运行。这一点和 Linux LWP 表现一致。

四、创建、切换、销毁开销

1. 创建

  • 创建进程 CreateProcess:开销巨大。系统新建独立 EPROCESS、全新地址空间、拷贝 PE 镜像、初始化句柄表;
  • 创建线程 CreateThread:开销小。仅新建 ETHREAD、分配线程栈,直接复用父进程全部资源。

2. 上下文切换

  1. 进程切换:必须切换页表,刷新 TLB、缓存,开销极高;
  2. 同进程线程切换:地址空间不变,不用换页表,只切换寄存器,开销很小;和 Linux 性能表现逻辑相同。

3. 崩溃退出规则

  1. 任意线程触发未捕获异常崩溃:整个进程直接终止,所有线程、全部资源销毁;
  2. 主线程退出不代表进程结束,只要还有任意工作线程在运行,进程会继续存活;

这里和 Linux 有区别:Linux 主线程 pthread_exit 后,若无其他线程进程才销毁;Windows 主线程 return 只是主线程结束,其他线程照常跑。

五、信号 / 异常机制区别(和 Linux 一大不同)

  1. Linux:信号是线程组共享 + 线程私有阻塞掩码;
  2. Windows:没有 “信号” 这套体系,用结构化异常 SEH,异常是绑定到单个线程的。某条线程崩溃只会在该线程抛出异常,可在线程内部捕获;若未捕获才杀死整个进程。

六、进程间 / 线程间通信

  1. 同进程线程:直接读写共享内存,配合临界区 CRITICAL_SECTION(轻量锁,用户态);
  2. 进程间隔离强,只能用 Windows 专属 IPC:管道、邮槽、共享内存文件映射、COM、窗口消息、命名互斥体等。

七、Windows vs Linux 核心模型对比

维度 Windows Linux
内核对象 进程 EPROCESS、线程 ETHREAD 两套独立结构体 统一 task_struct,靠资源共享标记区分
进程是否可调度 进程只是容器,不能被调度 单线程进程 = 可调度 task_struct
主线程退出行为 主线程结束,其他线程仍可运行 主线程退出,若无其他线程则进程销毁
异常 / 信号 异常绑定单线程 SEH 信号分线程组共享、线程私有掩码
实现线程方式 CreateThread 直接创建内核线程 1:1 pthread_create 基于 clone () 创建 LWP 1:1

八、极简总结 Windows 进程线程定义

  1. Windows 进程:承载虚拟内存、内核句柄、权限的隔离资源容器,本身无法被 CPU 执行;
  2. Windows 线程:依附于进程的独立调度实体,保存运行上下文,是操作系统调度 CPU 的最小单位;
  3. 同进程线程共享全部内存与内核句柄,切换成本低;进程之间完全隔离,交互必须依靠 IPC。

协程完整通俗讲解,结合进程 / 线程对比

1. 一句话定义

协程(Coroutine)是用户态、由代码手动调度的轻量级执行流,完全不依赖操作系统内核,没有内核切换开销。进程、线程是操作系统内核管理;协程是应用程序自己管理

2. 先分清三层执行单元(从上到下)

1)进程(内核 task_struct,资源容器)

独立地址空间,切换要换页表、刷新缓存,开销极大。

2)线程(Linux LWP,内核调度单元)

同进程共享资源,但切换要陷入内核、保存 CPU 寄存器,有系统调用开销,由 OS 时间片强制切换。

3)协程(用户态执行流,程序自行调度)

跑在某一个线程内部,全程不进内核,切换只保存少量自定义上下文,开销远小于线程;没有 OS 自动抢占,只能主动让出 CPU。

3. 协程核心两大特性

① 用户态调度,无内核参与

线程切换流程:触发中断 / 系统调用 → 进入内核态 → 保存 thread_struct 寄存器上下文 → 换任务。协程切换流程:纯用户代码跳转,只保存栈、局部变量、程序计数器,不触发内核,速度快几个数量级。

② 非抢占式,主动让出(重点区别线程)

  • 线程:操作系统时间片到了,强制剥夺CPU(抢占式),你代码跑一半也会被切走;
  • 协程:只有代码主动调用 yield/await/ 切换函数时,才会交出执行权;代码不主动让出,其他协程永远得不到运行机会。

4. 协程的上下文是什么?

每个协程只保存少量信息:

  1. 私有栈(很小,几 KB,线程栈默认 8MB)
  2. 当前代码执行位置(指令指针)
  3. 局部变量、寄存器快照没有 task_struct、不用维护内核调度队列。

5. 举个最简单的例子理解

def foo():
    print("协程A开始")
    yield  # 主动让出CPU,切到别的协程
    print("协程A恢复执行")

def bar():
    print("协程B运行")
    yield

主线程里调度器先跑 foo,遇到 yield 暂停 foo,保存现场;去跑 bar,再切回来。整个过程操作系统完全不知道有协程存在,内核只看到一个普通线程在运行。

6. 协程 vs 线程 关键对比

特性 内核线程 (LWP) 协程
管理者 Linux 内核调度器 应用层调度器(runtime)
切换位置 内核态 纯用户态
切换开销 大(上下文切换、缓存失效) 极小
调度方式 抢占式(OS 强制切) 协作式(主动 yield)
内存占用 栈 8MB 左右,数量有限 栈 KB 级,可开几十万
多核并行 支持,内核分发到多 CPU 核心 单线程内只能并发,无法利用多核;多线程 + 多协程才能并行

7. 一个极易踩坑的关键点

单个线程里的所有协程,只能并发,不能并行因为同一时刻这个线程只能在一个 CPU 核心上运行,协程只是轮流占用线程。想要协程真正并行,必须开多个操作系统线程,每个线程内部再跑一组协程(Go 的 GMP、Java 虚拟线程、Python 多进程 + 协程都是这个思路)。

8. 常见应用场景

IO 密集型程序(网络请求、文件读写、数据库查询):IO 阻塞时线程会被操作系统挂起(进入睡眠状态),浪费 CPU;协程遇到 IO 时主动让出执行权,调度器切去跑其他就绪协程,CPU 利用率极高。例:Go goroutine、Python async/await、Lua 协程、Java Virtual Thread。

极简总结

协程是跑在线程内部、程序自行调度、主动让出、低开销的轻量级子程序;和内核无关,没有 task_struct,解决 IO 密集场景下线程切换成本高、线程数量受限的问题。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐