[001]从操作系统层面看锁的逻辑

从操作系统层面,锁 (Lock) 是一种同步机制,用于控制多个线程或线程对共享资源的访问,防止竞态条件(race condition).常见的锁包括互斥锁(mutex)、读写锁(read-write lock)、自旋锁(spinlock)等。下面逐一分析其原理,从内核实现,CPU指令,调度机制等角度解释。

1.互斥锁(Mutex)

原理

作用:确保同一时刻只有一个线程/进程访问临界区。

实现机制:基于原子操作和睡眠/唤醒机制。

操作系统实现细节

1.用户态尝试加锁(快速路径):

通常用 原子CAS (Compare-And-Swap) 尝试将锁状态从"未占用"变为已经占用。

成功则进入临界区,失败则进入下一步。

  1. 内核态挂起(慢路径):

如果锁被占用,则线程被阻塞,进入等待队列(入Linux的futex队列)

等待唤醒时才尝试重新加锁。

3.解锁时唤醒等待线程

解锁线程将锁状态置为 未占用 并唤醒一个或者多个等待线程。

Linux示例:

Linux 中pthread_mutex实际使用了futex(fast userspace mutex)

futex 运行用户态,快速获取锁,失败时才陷入内核挂起,避免频繁陷入内核态。

二、自旋锁(Spinlock )

原理

不会挂起线程,而是获取不到锁时,持续循环检查锁状态("忙等待")

适用于临界区非常短、线程不会被长时间阻塞的场景(如内核中断上下文)

实现方式

使用原子质量(如xchg,cmpxhcg)实现加锁

CPU指令层级提供如LOCK CMPXCHG来保证总线原子性。

缺点

占用CPU资源,等待时间线程无法做其他工作。

多核系统上会导致缓存一直性流量(chache coherence traffice)增加。

三、读写锁(Read-Write Lock)

原理

允许多个读者共享访问,但写者必须独占。

优化了读多写少的场景。

实现机制

通常维护一个计数器记录读者数量。

写线程必须等待所有读者释放锁后才能进入。

内核或者用户态原子操作与条件变量管理状态

操作系统支持

POSIX提供pthread_rwlock ,Linux 内部实现使用类似rw_semaphore.

四、信号量(Semaphore)

原理

计数信号量可控制对资源的访问数量

二值信号量可以作为互斥锁的替代。

实现机制

内核维护一个计数器,P (wait) 操作将其减一,若<0则阻塞;V(signal )操作将其加一,唤醒等待线程

五、实现关键点:从硬件到内核

层级 关键点
CPU 提供原子操作:CMPXCHG,XCHG,LL/SC (ARM/MIPS)
缓存一致性 确保多核之间对锁变量的访问保持一致(MESI协议)
内核调度器 维护等待队列,挂起线程,唤醒线程
系统调用 用户态锁失败后,通过futex进入内核挂起

六、总结与对比

锁类型 是否阻塞线程 性能 场景
互斥锁 较好 通用
自旋锁 否(忙等) 非常高(短临界区) 内核、无阻塞上下文
读写锁 优于互斥(读多) 多读少些场景
信号量 适中 计数共享资源控制
相关推荐
阿里小阿希3 小时前
Vue3 + Element Plus 项目中日期时间处理的最佳实践与数据库设计规范
数据库·设计规范
白鹭4 小时前
MySQL源码部署(rhel7)
数据库·mysql
666和7775 小时前
Struts2 工作总结
java·数据库
还听珊瑚海吗5 小时前
SpringMVC(一)
数据库
星期天要睡觉6 小时前
MySQL 综合练习
数据库·mysql
Y4090016 小时前
数据库基础知识——聚合函数、分组查询
android·数据库
JosieBook7 小时前
【数据库】MySQL 数据库创建存储过程及使用场景详解
数据库·mysql
处女座_三月7 小时前
改 TDengine 数据库的时间写入限制
数据库·sql·mysql