当前位置: 首页 > news >正文

[每周一更]-(第152期):Go中的CAS(Compare-And-Swap)锁原理详解

在这里插入图片描述

CAS锁基本概念

CAS锁(Compare-And-Swap Lock)是一种基于原子比较交换操作实现的轻量级同步机制,属于自旋锁的一种实现方式。

核心特点

  • 非阻塞同步:线程不会主动挂起,而是通过循环尝试获取锁
  • 硬件支持:直接利用CPU的原子指令实现
  • 乐观锁策略:假设竞争不激烈,适合短临界区场景

CAS基本概念

CAS(Compare-And-Swap,比较并交换)是一种原子操作,它是现代并发编程的基石之一。CAS操作包含三个基本操作数:

  • 内存位置(V)
  • 预期原值(A)
  • 新值(B)

操作语义:“我认为位置V的值应该是A,如果是,那么将V的值更新为B,否则不做任何修改并告诉我当前实际值”

CAS在Go中的实现

在Go语言中,CAS操作主要通过sync/atomic包实现:

package atomicfunc CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
// 其他类型的CAS操作...

CAS的工作原理

CAS操作的伪代码表示:

func CompareAndSwap(addr *T, old, new T) bool {if *addr == old {*addr = newreturn true}return false
}

关键点

  1. 整个操作是原子性的(由CPU特殊指令保证)
  2. 操作是乐观的:假设不会发生冲突,冲突时重试
  3. 无阻塞:线程不会主动挂起

用CAS实现自旋锁

type SpinLock struct {state *int32 // 0表示未锁定,1表示锁定
}const free = 0
const locked = 1func (l *SpinLock) Lock() {for !atomic.CompareAndSwapInt32(l.state, free, locked) {// 可加入runtime.Gosched()避免过度占用CPU}
}func (l *SpinLock) Unlock() {atomic.StoreInt32(l.state, free)
}

CAS与互斥锁(Mutex)的区别

特性CAS自旋锁互斥锁
实现方式循环尝试直到成功(硬件原子操作)操作系统系统调用
阻塞方式忙等待(消耗CPU)线程挂起(不消耗CPU)
适用场景临界区操作非常快临界区操作耗时
线程切换
内存开销很小较大
公平性通常不公平可实现公平

CAS锁关键特性

特性说明
原子性由CPU指令保证比较和交换操作的原子性
自旋等待获取不到锁时会循环重试而非线程挂起
无调度开销不涉及操作系统内核调度
内存一致性保证对锁变量的修改对所有线程立即可见
轻量级相比互斥锁(Mutex)消耗更少资源

CAS的典型应用场景

适合场景

  • 临界区操作非常快(纳秒/微秒级)
  • 低竞争环境(线程争用不激烈)
  • 需要极高性能的场景

典型用例

  1. 内核数据结构保护
  2. 无锁数据结构实现基础
  3. 高性能计数器
  4. 状态标志更新

具体示例

  1. 计数器原子递增

    func atomicIncrement(addr *int32) {for {old := atomic.LoadInt32(addr)new := old + 1if atomic.CompareAndSwapInt32(addr, old, new) {return}}
    }
    
  2. 无锁数据结构:如无锁队列、无锁栈等

  3. 状态标志更新:当需要基于当前状态原子性更新到新状态时

  4. Ticket Lock(票号锁)

    解决公平性问题,按请求顺序分配锁

    type TicketLock struct {next  int32owner int32
    }func (l *TicketLock) Lock() {t := atomic.AddInt32(&l.next, 1) - 1for atomic.LoadInt32(&l.owner) != t {runtime.Gosched()}
    }
    

CAS的优缺点

优点

  • 无上下文切换:无阻塞,线程不会挂起
  • 低延迟:轻量级,适合简单操作,获取锁的速度快(约10-100个CPU周期)
  • 可扩展性:在多核系统上表现良好,避免死锁问题(因为没有持有锁的概念)

缺点

  • ABA问题:值从A变为B又变回A,CAS会误认为没变化
    • 解决方法:使用版本号或标记指针
  • 循环开销:高竞争时大量CPU浪费在重试
  • 只能保护一个变量:复杂操作需要多个CAS组合

Go中的CAS实战示例

实现线程安全的计数器

type Counter struct {value int64
}func (c *Counter) Increment() {for {old := atomic.LoadInt64(&c.value)new := old + 1if atomic.CompareAndSwapInt64(&c.value, old, new) {return}}
}func (c *Counter) Value() int64 {return atomic.LoadInt64(&c.value)
}

实现简单的自旋锁

type SpinLock struct {flag int32
}func (sl *SpinLock) Lock() {for !atomic.CompareAndSwapInt32(&sl.flag, 0, 1) {// 可适当加入退让策略runtime.Gosched()}
}func (sl *SpinLock) Unlock() {atomic.StoreInt32(&sl.flag, 0)
}

CAS的底层硬件支持

现代CPU通常提供CAS指令:

  • x86: CMPXCHG指令
  • ARM: LDREX/STREX指令对
  • Go的atomic包会针对不同平台使用最优实现

使用建议

  1. 简单操作用CAS:如标志设置、计数器增减
  2. 复杂操作用Mutex:当需要保护多个变量或复杂逻辑时
  3. 注意竞争程度:高竞争场景CAS性能可能反而不如Mutex
  4. 避免过度自旋:长时间获取不到锁应退让或切换策略

为什么需要CAS

  1. 无锁编程基础:构建无锁数据结构(队列、栈等)的必要原语
  2. 性能优势:比互斥锁更轻量级的同步方式
  3. 硬件映射:直接利用CPU的原子指令能力
  4. 并发控制:实现更高效的同步机制(如自旋锁、信号量等)

CAS是构建无锁算法的基础,理解CAS对深入掌握并发编程至关重要。在Go中,大多数时候sync.Mutex已经足够好,但在性能关键路径上,合理使用CAS可以带来显著性能提升。Go的sync.Mutex:早期版本使用纯自旋,现在实现为自适应锁

http://www.dtcms.com/a/301544.html

相关文章:

  • Java面试宝典:MySQL性能优化
  • ES6模块详解:核心语法与最佳实践
  • 编码器和解码器风格的Transformer架构
  • 使用vue2和 element-ui 做一个点餐收银台系统前端静态项目
  • 数据江湖的“三国演义”:数据仓库、数据湖与湖仓一体的全景对比
  • Gradio全解8——ChatInterfaceChatbot:聊天界面类与聊天机器人(4)——返回复杂响应与直接修改Chatbot值
  • Java Ai(day03)
  • 【秋招笔试】7月26日科大讯飞秋招第一题
  • 【最新最完整】SpringAI-1.0.0开发MCP Server,搭建MCP Client 实战笔记(进阶+详细+完整代码)
  • AI Agent学习
  • MyBatis-Plus IService 接口全量方法实现与测试(续)
  • 【c++】从 “勉强能用” 到 “真正好用”:中文问答系统的 200 行关键优化——关于我用AI编写了一个聊天机器人……(16)
  • 中级全栈工程师笔试题
  • DP之背包基础
  • 详解力扣高频SQL50题之180. 连续出现的数字【困难】
  • CPA会计-5- 投资性房地产
  • 逆向入门(42)程序逆向篇-riijj_cm_20041121
  • 生态环境大数据技术专业的深度解析
  • 物理实验仿真平台设计与实现(抛体运动与电磁场交互)
  • 构建可扩展的状态系统:基于 ArkTS 的模块化状态管理设计与实现
  • MPI环形AllReduce算法实现与深度解析
  • lombok插件@NoArgsConstructor、@AllArgsConstructor、@RequiredArgsConstructor的区别
  • RS485 半双工系统中 DE 控制端默认 0 的技术原理与工程实践
  • (实用教程)Linux操作系统(二)
  • 零基础 “入坑” Java--- 十五、字符串String
  • 【I】题目解析
  • Spring MVC设计精粹:源码级架构解析与实践指南
  • 发布 VS Code 扩展的流程:以颜色主题为例
  • Python学习-----1.认识Python
  • 墨者:X-Forwarded-For注入漏洞实战