闽公网安备 35020302035485号
type Uint128 struct {
d [3]uint64
m sync.Mutex
}
然后类似标准库 atomic 中对各种整数的操作,它也提供了类似的方法:func AddUint128(ptr *Uint128, incr [2]uint64) [2]uint64 func CompareAndSwapUint128(ptr *Uint128, old, new [2]uint64) bool func LoadUint128(ptr *Uint128) [2]uint64 func StoreUint128(ptr *Uint128, new [2]uint64) func SwapUint128(ptr *Uint128, new [2]uint64) [2]uint64 func OrUint128(ptr *Uint128, op [2]uint64) [2]uint64 func AndUint128(ptr *Uint128, op [2]uint64) [2]uint64 func XorUint128(ptr *Uint128, op [2]uint64) [2]uint64可以看到,除了正常的 Add、CAS、Load、Store、Swap 函数,还贴心的提供了 Or、And、Xor 三个位操作的函数。
n := &atomic128.Uint128{}
v := atomic128.LoadUint128(n) // [2]uint64{0, 0}
atomic128.StoreUint128(n, [2]uint64{1, ^uint64(0)})
v = atomic128.LoadUint128(n) // [2]uint64{1, ^uint64(0)}
v = AddUint128(n, [2]uint64{2, 40})
v = atomic128.LoadUint128(n) // [2]uint64{3, 40}
v = atomic128.SwapUint128(n, [2]uint64{4, 50})
v = atomic128.LoadUint128(n) // [2]uint64{4, 50}
v = atomic128.CompareAndSwapUint128(n, [2]uint64{4, 50}, [2]uint64{5, 60})
v = atomic128.LoadUint128(n) // [2]uint64{5, 60}
v = atomic128.OrUint128(n, [2]uint64{0, 0})
v = atomic128.LoadUint128(n) // [2]uint64{5, 60}
atomic128 的实现https://go101.org/article/memory-layout.html https://pkg.go.dev/sync/atomic#pkg-note-BUG通过包含三个 Uint64 元素的数组,我们总能通过下面的方法得到 128 位对齐的地址:
func addr(ptr *Uint128) *[2]uint64 {
if (uintptr)((unsafe.Pointer)(&ptr.d[0]))%16 == 0 { // 指针已经128位对齐
return (*[2]uint64)((unsafe.Pointer)(&ptr.d[0]))
}
return (*[2]uint64)((unsafe.Pointer)(&ptr.d[1])) // 必然ptr.d[1]是128位对齐的 (AMD64架构)
}
通过变量useNativeAmd64判断 CPU 是否支持CMPXCHG16B指令:func init() {
useNativeAmd64 = cpuid.CPU.Supports(cpuid.CX16)
}
如果不支持,回退到使用 Mutex 实现一个低效的 atomic 128bit 原子操作:func CompareAndSwapUint128(ptr *Uint128, old, new [2]uint64) bool {
if runtime.GOARCH == "amd64" && useNativeAmd64 {
return compareAndSwapUint128amd64(addr(ptr), old, new)
}
// 不支持CMPXCHG16B指令,使用Mutex
ptr.m.Lock()
v := load(ptr)
if v != old {
ptr.m.Unlock()
return false
}
store(ptr, new)
ptr.m.Unlock()
return true
}
如果支持CMPXCHG16B指令,直接调用compareAndSwapUint128amd64函数:TEXT ·compareAndSwapUint128amd64(SB),NOSPLIT,$0 MOVQ addr+0(FP), BP MOVQ old+8(FP), AX MOVQ old+16(FP), DX MOVQ new+24(FP), BX MOVQ new+32(FP), CX LOCK CMPXCHG16B (BP) SETEQ swapped+40(FP) RET主要依赖CMPXCHG16B实现。
根据比较结果,设置相应的标志位。