什么是“代码临界区”?

在并发程序里,“代码临界区”是指那一小段必须排队使用的共享地带:任何时刻只能有 1 个执行线程进去,否则就像两辆车同时冲进单车道桥——不是撞车就是掉河。临界区的核心意义,就是用各种互斥技术(锁、原子操作等)把这座“桥”管起来,确保里面对共享数据的读改写具有一致性和可预期性。

临界区是什么?

在操作系统教材里,临界区(critical section)是访问共享资源的那段代码;若同时进入者超过 1 个就会出现“竞态条件”——执行顺序不同导致结果错乱。
经典定义强调三个条件:互斥(一次只能进 1 个)、前进(没人抢时不能阻塞自己)、有界等待(永远轮得到其他线程)。

类比 1:单车道桥

想象一座只能让一辆车通行的窄桥:

  • 桥面 = 共享资源(内存、文件、寄存器)。

  • 上桥的交通灯 = 互斥锁。

  • 若南来车已在桥上,北来车必须在灯前等待,直到对向车过桥并放行。

真实工程里,开发者通过 mutex_lock()spin_lock() 把“交通灯”放在临界区入口,确保别的 CPU 不会在你修改链表时闯进来。

类比 2:家里的卫生间

只有一间卫生间:

  1. 把手锁住→表示“有人”;

  2. 其他家庭成员在门外忙等(转门把)或排队(坐沙发等通知)——对应自旋锁和互斥锁的差别;

  3. 出来时开锁并喊“下一个”。

软件里的锁变量就是那把门锁;等待策略不同造就了自旋锁(在原地“捏门把”)和互斥锁(让出 CPU 去干别的)。

技术原理(简化版)

1. 检测&占用

CPU 用一条“读‑改‑写”原子指令尝试把锁从 0 改成 1。成功→进入;失败→等待。

2. 保证互斥

硬件提供 LL/SCCMPXCHG 指令,确保别的核心不可能在中途看到半修改的数据。

3. 退出&唤醒

离开临界区时把锁设回 0,并(若是互斥锁)唤醒下一位等待者。

什么时候一定要用临界区?

场景原因
引用计数++/--并发更新同一整数,若不互斥计数会丢失。
链表/队列头指针修改两线程同时改head会丢节点或形成环。
硬件寄存器读改写多核同时写控制位会触发未知硬件状态。

若只是读不写,或操作的是线程私有变量,就不必进入临界区。

选哪种“交通灯”?

锁类型等待方式适合临界区长度
自旋锁原地忙等,CPU 空转极短(µs 级);如中断处理共享计数器。
互斥锁沉睡排队,CPU 可做别事较长操作;如磁盘 I/O、内存分配。
原子操作无锁,靠硬件一次搞定单变量更新;如atomic_inc()

若乱用会怎样?

  • 死锁:两辆车对向堵桥头,谁也不退;编程里是锁顺序不当。

  • 忙等浪费:自旋锁用在长任务会让其他核空转,CPU 利用率暴跌。

  • 硬件一致性风暴:锁变量所在缓存行反复失效,系统抖动。

小结

临界区就是程序里的单车道桥/独卫——必须一人一车按序通过。互斥锁、自旋锁、原子操作就是门锁/交通灯的不同实现,负责让线程排队、避免争抢和数据事故。只要记住“共享+修改=要互斥”这条经验,你就能判断什么时候该在代码里划出临界区并加以保护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值