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

六、总结与对比

锁类型 是否阻塞线程 性能 场景
互斥锁 较好 通用
自旋锁 否(忙等) 非常高(短临界区) 内核、无阻塞上下文
读写锁 优于互斥(读多) 多读少些场景
信号量 适中 计数共享资源控制
相关推荐
zew104099458814 小时前
PyCharm【2023.2.5】下使用编辑器自带的连接功能,连接MySQL数据库
数据库·mysql·pycharm·编辑器·连接mysql
正在走向自律15 小时前
Oracle迁移至金仓数据库:PL/SQL匿名块执行失败的深度排查指南
数据库·sql·oracle·国产数据库·电科金仓
Evan芙20 小时前
RDBMS的库、表、视图、索引、设计范式总结
数据库
一叶飘零_sweeeet20 小时前
从单机到集群:Redis部署全攻略
数据库·redis·缓存
soft200152520 小时前
MySQL Buffer Pool深度解析:LRU算法的完美与缺陷
数据库·mysql·算法
C++业余爱好者20 小时前
SQL Server 中数据库管理系统、数据库实例与数据库的关系与区别
数据库·oracle
保护我方头发丶20 小时前
ESP-wifi-蓝牙
前端·javascript·数据库
tgethe21 小时前
mysql-视图详解
数据库·mysql
漂亮的小碎步丶1 天前
【6】数据库事务与锁机制详解(附并发结算案例)
数据库·事务·锁机制
北极糊的狐1 天前
MySQL报错Communications link failure(通信链路失败)
数据库·mysql