[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进入内核挂起

六、总结与对比

锁类型 是否阻塞线程 性能 场景
互斥锁 较好 通用
自旋锁 否(忙等) 非常高(短临界区) 内核、无阻塞上下文
读写锁 优于互斥(读多) 多读少些场景
信号量 适中 计数共享资源控制
相关推荐
坚定信念,勇往无前2 小时前
mongodb的日志分割
数据库·mongodb
oradh6 小时前
Oracle TX 锁 Mode 4(Share)问题排查总结
数据库·oracle·tx 锁 mode 4·oracle tx 锁
yi.Ist6 小时前
数据定义语言-DDL操作
数据库·学习·mysql·oracle·大海豚
2601_963282778 小时前
工程项目、政企采购为什么优先选择对讲机批量采购?
数据库
Doraemomo8 小时前
SQLite数据库
数据库·sqlite
云贝教育-郑老师8 小时前
MySQL 的“黑匣子“:Performance Schema 把数据库内部变成一张可查的表
数据库·mysql
这个DBA有点耶10 小时前
同城双活落地的三座山:网络延迟、脑裂预防、反向同步
数据库·架构·dba
青春之我_XP10 小时前
MySQL 常用日期函数 实战指南
数据库·sql·mysql·数据分析·数据库开发·日期函数
Nturmoils10 小时前
sys_dump 备了库,角色和权限别漏在外面
数据库