什么是Go语言的 CAS

发布于 1周前 作者 nodeper 最后一次编辑是 5天前 来自 问答

什么是Go语言的 CAS

CAS 的全称为 Compare And Swap,直译就是比较交换。是一条 CPU 的原子指 令,其作用是让 CPU 先进行比较两个值是否相等,然后原子地更新某个位置的 值,其实现方式是给予硬件平台的汇编指令,在 intel 的 CPU 中,使用的cmpxchg 指令,就是说 CAS 是靠硬件实现的,从而在硬件层面提升效率。

简述过程是这样:

假设包含 3 个参数内存位置(V)、预期原值(A)和新值(B)。V 表示要更新变量的 值,E 表示预期值,N 表示新值。仅当 V 值等于 E 值时,才会将 V 的值设为 N, 如果 V 值和 E 值不同,则说明已经有其他线程在做更新,则当前线程什么都不 做,最后 CAS 返回当前 V 的真实值。CAS 操作时抱着乐观的态度进行的,它总 是认为自己可以成功完成操作。基于这样的原理,CAS 操作即使没有锁,也可以发现其他线程对于当前线程的干扰。

1 回复

什么是Go语言的 CAS

Go语言中的CAS(Compare-And-Swap)是一种用于实现原子操作的低层次同步原语。CAS操作涉及三个参数:内存位置(V)、预期原值(A)和新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。这个操作是原子的,意味着它在执行过程中不会被线程调度机制中断。

CAS通常用于实现无锁编程,特别是在多线程环境下对共享资源的访问和修改,如实现自旋锁、原子变量等。在Go语言中,sync/atomic包提供了CAS操作的支持,使得开发者可以在Go程序中方便地利用CAS来实现并发控制。

示例代码

下面是一个使用Go语言sync/atomic包中的CompareAndSwapInt32函数实现的CAS操作的示例:

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var counter int32 = 0

	// 假设我们有两个goroutine尝试更新counter的值
	go func() {
		for i := 0; i < 1000; i++ {
			// 尝试将counter的值从当前值更新为当前值+1
			// 注意这里使用的是CompareAndSwapInt32函数
			for {
				old := atomic.LoadInt32(&counter)
				new := old + 1
				if atomic.CompareAndSwapInt32(&counter, old, new) {
					break // 更新成功,跳出循环
				}
				// 如果更新失败(说明counter的值在Load和CAS之间被其他goroutine修改了),则重新尝试
			}
		}
	}()

	// 另一个goroutine也做同样的操作
	go func() {
		for i := 0; i < 1000; i++ {
			for {
				old := atomic.LoadInt32(&counter)
				new := old + 1
				if atomic.CompareAndSwapInt32(&counter, old, new) {
					break
				}
			}
		}
	}()

	// 等待一段时间让上面的goroutine执行
	// 注意:实际使用中应该使用更可靠的同步机制来等待goroutine完成,如sync.WaitGroup
	// 这里为了简化示例,仅使用简单的延时
	// 注意:在生产代码中避免使用time.Sleep来同步并发操作
	time.Sleep(1 * time.Second)

	fmt.Println("Final counter:", counter)
	// 期望输出接近2000,但实际输出可能因并发执行的具体顺序而略有不同
}

// 注意:上面的代码示例包含了并发执行的元素,但由于主goroutine直接使用了time.Sleep来等待,
// 这并不是一种推荐的做法。在实际应用中,应使用更合适的并发控制机制(如sync.WaitGroup)。

注意:由于并发执行的特性,上述代码中的Final counter输出可能并不是精确的2000,因为两个goroutine之间的执行顺序是并发的,且可能相互交错。此外,示例中使用了time.Sleep来模拟等待goroutine完成,这在实际应用中是不推荐的,因为它不能保证goroutine一定会在这个时间内完成。更合适的做法是使用sync.WaitGroup或其他同步机制来等待goroutine完成。

回到顶部