funcStoreInt32(addr *int32, val int32)funcStoreInt64(addr *int64, val int64)funcStoreUint32(addr *uint32, val uint32)funcStoreUint64(addr *uint64, val uint64)funcStoreUintptr(addr *uintptr, val uintptr)funcStorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
sync.atomic.Value
上面提供大量的针对数值和指针类型的原子操作相关方法,为了扩大原子操作的范围,在 Go 1.4 的加入了sync.atomic.Value
type Value struct{
v interface{}}
value使用示例: value 使用起来非常简单可以把它当作一个容器,可以将值存入该容器中,然后通过容器取值,通过容器保证了原子性的,提供了Load() 和 Store() 两个方法
Load(): 安全地从内存中读取值,
Store(): 将值安全地存入内存
type S struct{
a int}funcmain(){var v atomic.Value
s := S{1}
v.Store(s)
p := v.Load()
fmt.Println(p.(S).a)}
二. sync.atomic 源码分析
1. ifaceWords
了解sync.atomic底层,首先要了解Go底层提供的一个私有的结构体 ifaceWords,内部含 typ 和 data 两个指针类型属性,前者表示值的真实类型,后者表示值的“值”,通过unsafe.Pointer 转换成 ifaceWords, 可以得到 interface{} 真实的类型和值
type ifaceWords struct{
typ unsafe.Pointer
data unsafe.Pointer
}
如果不是第一次存储数据,进行数据类型校验,校验成功后调用StorePointer(),把新值 x 的类型和值存储在 v 的地址上
func(v *Value)Store(x interface{}){//1.判断是否为nilif x ==nil{panic("sync/atomic: store of nil value into Value")}//2.将原值与现在添加的值强转为ifaceWords类型//将Value类型的对象v转成ifaceWords类型的对象,因为v的底层结构与ifaceWords是相同的
vp :=(*ifaceWords)(unsafe.Pointer(v))//将入参对象x转成ifaceWords类型的对象,x为interface{}类型,底层结构与ifaceWords是相同的
xp :=(*ifaceWords)(unsafe.Pointer(&x))//3.自旋for{//获取原值的真实数据类型
typ :=LoadPointer(&vp.typ)//如果原值为nil,说明是第一次存储值 if typ ==nil{//禁止抢占,防止 GC 看到 unsafe.Pointer(^uintptr(0)) 这个奇怪的类型runtime_procPin()//通过原子性操作,存储数据,如果存储失败continue重试if!CompareAndSwapPointer(&vp.typ,nil, unsafe.Pointer(^uintptr(0))){//释放禁止抢占runtime_procUnpin()continue// 比较不通过,说明有别人在执行赋值,自旋等待}//分别将入参中的type和data存储到v中,注意这里是先存储data然后存储typ,//因为程序以typ是否设置完成,来判断整个存储操作全部完成StorePointer(&vp.data, xp.data)// 设置新置StorePointer(&vp.typ, xp.typ)// 设置类型runtime_procUnpin()return}//该判断返回true,说明赋值没结束,自旋等待ifuintptr(typ)==^uintptr(0){continue}//4.当执行到此处说明不是第一次存储,判断此次添加的数据,类型与原始值是否相同if typ != xp.typ {panic("sync/atomic: store of inconsistently typed value into Value")}//把 x 写入 v// 只有第一次需要设置 tpy, 后面只需要设置 data StorePointer(&vp.data, xp.data)return}}
3. Load()获取
Load相对简单, 通过 ifaceWords 拿到 v 的真实类型,如果 v 中没有存值或正在写入,他会直接返回 nil,否则就把 v.data 和 v.typ 重新组装成 interface{} 返回
func(v *Value)Load()(x interface{}){
vp :=(*ifaceWords)(unsafe.Pointer(v))
typ :=LoadPointer(&vp.typ)if typ ==nil||uintptr(typ)==^uintptr(0){// First store not yet completed.returnnil}
data :=LoadPointer(&vp.data)
xp :=(*ifaceWords)(unsafe.Pointer(&x))
xp.typ = typ
xp.data = data
return}