线程的理解

线程理解

一、 进程与线程的本质区别

  • 进程是资源分配的最小单位 :
    • 内核为每个进程分配独立的虚拟地址空间(页表)、文件描述符表、信号处理规则等。
    • 关键点:进程之间是"老死不相往来"的,内存隔离是默认状态。
  • 线程是CPU调度的最小单位 :
    • 线程是寄生在进程里的执行流。它没有独立的地址空间,只拥有维持执行所必需的最少资源:栈(Stack)、寄存器上下文(Context)、线程ID(TID)。
    • 关键点:同一进程内的线程共享该进程的"家底"(内存、文件句柄),这使得它们之间的通信成本几乎为零,但也带来了数据竞争的风险。

二、 共享资源的底层透视(重点)

1. 代码段与数据段(Text & Data Segment)

  • 底层实现 :所有线程共用同一套页表映射。这意味着,如果线程A修改了全局变量 global_count,线程B在下一次读取时,看到的是修改后的值(前提是缓存一致性协议生效)。
  • 隐患 :
    • 只读安全 :代码段是只读的,所以多线程调用同一个函数(如 printf)是安全的,不需要加锁。
    • 读写危险:全局变量、静态变量位于数据段或BSS段,是所有线程的"公共厕所",必须加锁(Mutex)或使用原子操作(Atomic)保护。

2. 文件描述符表(File Descriptor Table)

  • 底层实现 :这是内核维护的一张表,记录了进程打开了哪些文件/Socket。线程共享这张表,意味着它们共享文件的偏移量(Offset)。
  • 隐患 :
    • 并发读写冲突:如果线程A和线程B同时向同一个文件描述符写数据,且没有加锁,数据会交错混乱。
    • 生命周期管理 :线程A关闭了某个Socket(close(fd)),线程B如果此时还在尝试读写这个fd,会直接报错 EBADF。这是多线程网络编程中常见的Bug。

3. 信号处理(Signal Handling)

这是一个极易混淆的点,必须区分处理方式 与屏蔽字:

  • 共享部分(处理方式) :SIG_IGN(忽略)、SIG_DFL(默认)或自定义的处理函数(Handler)。这些是注册在进程控制块(PCB)里的。如果你在线程A里把 SIGINT 设为忽略,整个进程的所有线程都会忽略它。
  • 私有部分(屏蔽字 Mask):每个线程可以决定自己"暂时不想收哪些信号"。这通常用于关键代码段的保护。
  • 发送目标 :发给进程的信号(如 kill -9 pid),内核会随机挑选一个未屏蔽该信号的线程来执行处理函数。

4. 其他环境信息

  • 当前工作目录(CWD) :进程级共享。线程A调用 chdir("/tmp"),线程B紧接着打开相对路径文件 ./data.txt,实际上打开的是 /tmp/data.txt。这在复杂的多线程程序中是一个巨大的隐形炸弹。
  • 用户ID/组ID :决定了进程的权限。一旦改变(如 setuid),所有线程的权限都会瞬间改变。

三、 线程私有成员

为了保证多线程能独立运行而不互相干扰,每个线程必须有自己的一套"私有成员

  1. 栈空间(Stack) :
    • 这是线程最核心的私有资源。函数调用的局部变量、返回地址都存在这里。
    • 注意:栈溢出(Stack Overflow)通常只会搞挂当前线程,而不会直接搞挂整个进程(除非破坏了关键的共享数据结构)。
  2. 寄存器上下文(Register Context) :
    • 包括程序计数器(PC,指向下一条指令)、栈指针(SP)、通用寄存器等。
    • 原理:当操作系统进行线程切换时,本质上就是把当前线程的寄存器值保存到内存(TCB中),再把下一个线程的寄存器值加载到CPU。这就是"上下文切换"。
  3. errno :
    • C语言标准库的全局变量 errno 在多线程环境下必须是线程私有的(通过 TLS 线程局部存储实现)。否则,线程A刚发生错误设置了 errno,还没等读取,就被线程B的成功操作覆盖了,导致错误诊断完全失效。
  4. 信号屏蔽字(Signal Mask) :
    • 允许线程根据自己的执行阶段,动态地屏蔽某些信号,防止被打断。

四、 四种进程/线程模型的

结合你提供的图片,我们来看这四种形态在实际工程中的取舍:

模型 核心特征 适用场景 致命弱点
单线程进程 简单、无锁、串行 简单的脚本、嵌入式控制逻辑、早期的 DOS 程序 I/O 阻塞即死机;无法利用多核 CPU。
多进程(多个单线程) 隔离性最强、稳定性高 Web 服务器的主控进程(如 Nginx Master)、安全性要求极高的系统 通信成本高(IPC);创建/切换开销大(需换页表)。
多线程(单进程多线程) 切换极快、通信零成本 高并发服务器(Tomcat, Go Runtime)、GUI 应用 "一损俱损"(一个线程野指针可能搞挂整个进程);调试困难。
多线程进程组 兼顾隔离与并发 现代浏览器(Chrome 每个标签页一个进程,进程内多线程)、大型数据库 架构极其复杂;资源消耗大。

线程是操作系统为了在"资源共享"和"独立执行"之间寻找平衡而创造的产物。

相关推荐
夜听莺儿鸣19 小时前
502-003_Linux 中断与异常(一):从Linux角度理解中断与异常
linux·中断与异常·linux中断
杨云龙UP20 小时前
TDengine 3.4.2.8 Community 三节点三副本生产集群部署实战(DNode/MNode/taosAdapter/Explorer)
大数据·linux·运维·数据库·tdengine·时序库
向成科技21 小时前
XC3576H工控主板|深度适配Ubuntu 26.04 LTS,释放边缘AI与工业开发新潜能
linux·人工智能·ubuntu·机器人·硬件·主板·边缘ai
Fcy6481 天前
Linux下 进程间关系与守护进程
linux·运维·服务器·守护进程
码农小韩1 天前
Linux驱动理论(二)——Linux字符设备驱动
linux·嵌入式软件开发·linux操作系统·linux应用开发·linux驱动理论
well06121 天前
Linux粘滞位与Makefile机制深度解析
linux·运维·服务器
再写一行代码就下班1 天前
linux sh脚本在windows修改导致无法使用解决方式
java·linux·centos
额额额对了1 天前
SPI通信
linux·c语言·汇编·单片机·嵌入式硬件·arm
子木HAPPY阳VIP1 天前
Ubuntu 关闭防火墙操作步骤
linux·运维·ubuntu
王振超wzc1 天前
嵌入式开发环境搭建--WM软件安装,Ubuntu操作系统安装
linux·运维·ubuntu