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

六、总结与对比

锁类型 是否阻塞线程 性能 场景
互斥锁 较好 通用
自旋锁 否(忙等) 非常高(短临界区) 内核、无阻塞上下文
读写锁 优于互斥(读多) 多读少些场景
信号量 适中 计数共享资源控制
相关推荐
数据知道9 分钟前
PostgreSQL 故障排查:万字详解如何找出数据库中的死锁
数据库·postgresql
AI_567817 分钟前
阿里云OSS成本优化:生命周期规则+分层存储省70%
运维·数据库·人工智能·ai
choke23320 分钟前
软件测试任务测试
服务器·数据库·sqlserver
龙山云仓21 分钟前
MES系统超融合架构
大数据·数据库·人工智能·sql·机器学习·架构·全文检索
IT邦德22 分钟前
OEL9.7 安装 Oracle 26ai RAC
数据库·oracle
jianghua00141 分钟前
Django视图与URLs路由详解
数据库·django·sqlite
那我掉的头发算什么42 分钟前
【Mybatis】Mybatis-plus使用介绍
服务器·数据库·后端·spring·mybatis
倔强的石头10643 分钟前
关系数据库替换用金仓:数据迁移过程中的完整性与一致性风险
数据库·kingbase
_Johnny_43 分钟前
ETCD 配额/空间告警模拟脚本
数据库·chrome·etcd
静听山水1 小时前
StarRocks查询加速
数据库