You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go中实现类似C(GCC内置)的__sync_fetch_and_add功能?

如何在Go中实现类似GCC __sync_fetch_and_add的功能

嘿,其实不用非得靠CompareAndSwap加while循环来绕弯路!你可能没留意到,Go的sync/atomic包已经能轻松搞定这个需求,而且方式比你想的更简洁高效。

最推荐的方式:利用Add系列函数返回值计算旧值

GCC的__sync_fetch_and_add是原子完成加法后返回更新前的旧值,而Go的atomic.AddInt32/AddInt64等函数返回的是更新后的新值。不过因为原子加法是一个完整的原子操作,我们可以通过简单的反向计算得到旧值:

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	var counter int32 = 10
	delta := int32(5)

	// 等价于GCC的__sync_fetch_and_add(&counter, delta)
	oldVal := atomic.AddInt32(&counter, delta) - delta
	fmt.Printf("旧值: %d, 更新后的值: %d\n", oldVal, counter)
	// 输出:旧值: 10, 更新后的值: 15
}

这种方式完全安全可靠——哪怕发生整数溢出(比如int32的最大值加1),由于Go的原子加法是按补码规则处理的,(新值 - delta)的结果也会准确等于原始的旧值,补码运算的特性保证了这一点。

用CAS循环实现(仅作原理参考,不推荐)

如果只是想理解底层逻辑,用CAS循环也能实现,但这种方式繁琐且性能不如直接用Add函数(毕竟Add是硬件指令级的原子操作):

func fetchAndAddInt32(addr *int32, delta int32) int32 {
	for {
		// 先原子读取当前值
		current := atomic.LoadInt32(addr)
		// 计算预期的新值
		expectedNew := current + delta
		// 尝试CAS更新,成功则返回旧值
		if atomic.CompareAndSwapInt32(addr, current, expectedNew) {
			return current
		}
		// 失败则循环重试,直到成功
	}
}

总结

优先选择第一种方法,用atomic.AddXXX的返回值减去delta来获取旧值,这是最简洁、最高效的实现方式,完全等价于GCC的__sync_fetch_and_add功能。

内容的提问来源于stack exchange,提问作者superK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:09:27