sync:一. 原子操作(atomic)
原子操作
原子操作是指在程序运行中不能被中断的操作,原子操作是无锁的常常是由CPU指令直接实现,而锁一般由操作系统的调度器实现,所以原子操作的效率一般更高。
golang中原子操作支持的类型有:int32、int64、uint32、uint64、uintptr、unsafe.Pointer
golang中原子操作的函数
增或减
函数名以Add开头,后面跟具体的类型。该方法接收两个参数,一个是内存地址,一个是需要加上的数值,并返回加或者减后的结果。
// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)
// AddUint32 atomically adds delta to *addr and returns the new value.
// To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)).
// In particular, to decrement x, do AddUint32(&x, ^uint32(0)).
func AddUint32(addr *uint32, delta uint32) (new uint32)
// AddInt64 atomically adds delta to *addr and returns the new value.
func AddInt64(addr *int64, delta int64) (new int64)
// AddUint64 atomically adds delta to *addr and returns the new value.
// To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)).
// In particular, to decrement x, do AddUint64(&x, ^uint64(0)).
func AddUint64(addr *uint64, delta uint64) (new uint64)
// AddUintptr atomically adds delta to *addr and returns the new value.
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
举使用的例子:
func main() {
var a int32
atomic.AddInt32(&a,20)
fmt.Println("a 的值:",a)
atomic.AddInt32(&a,-8)
fmt.Println("a 的值:",a)
}
查看输出
a 的值: 20
a 的值: 12
载入(Load)
函数名以Load开头,后面跟具体的类型。该方法接收一个地址,并返回该地址中的数据。
// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)
func LoadInt64(addr *int64) (val int64)
func LoadUint32(addr *uint32) (val uint32)
func LoadUint64(addr *uint64) (val uint64)
func LoadUintptr(addr *uintptr) (val uintptr)
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
存储(Store)
函数名以Store开头,后面跟具体的类型。该方法接收两个参数,一个是保存数据的地址,另外一个是要保存的值
该类主要负责将对应的值保存在相应的内存地址中。
// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)
func StoreInt64(addr *int64, val int64)
func StoreUint32(addr *uint32, val uint32)
func StoreUint64(addr *uint64, val uint64)
func StoreUintptr(addr *uintptr, val uintptr)
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
比较并交换
该操作简称 CAS(Compare And Swap)。 这类操作的前缀为 CompareAndSwap。该类方法接收3个参数:数据的地址,旧的值,新值。比较地址内的数据和旧数据是否相等。相等就把新值赋在该地址上并返回true。不等则直接返回false。
// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
交换(Swap)
函数名以Swap开头,后面跟具体的类型。该类方法接收一个地址和一个新值。将新值赋在地址上并返回旧的值。
// SwapInt32 atomically stores new into *addr and returns the previous *addr value.
func SwapInt32(addr *int32, new int32) (old int32)
func SwapInt64(addr *int64, new int64) (old int64)
func SwapUint32(addr *uint32, new uint32) (old uint32)
func SwapUint64(addr *uint64, new uint64) (old uint64)
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
atomic.Value
对原子操作的类型的扩展。从特定的类型扩展到任意类型。
Store
实现原子存储任意类型的值。
// Store sets the value of the Value to x.
// All calls to Store for a given Value must use values of the same concrete type.
// Store of an inconsistent type panics, as does Store(nil).
func (v *Value) Store(x interface{}) {
if x == nil {
panic("sync/atomic: store of nil value into Value")
}
// 将现有的值和要写入的值转换为ifaceWords类型,这样下一步就能获取到它们的原始类型和真正的值
vp := (*ifaceWords)(unsafe.Pointer(v))
xp := (*ifaceWords)(unsafe.Pointer(&x))
for {
// 获取现有的值的type
typ := LoadPointer(&vp.typ)
// 如果typ为nil说明这是第一次Store
if typ == nil {
// 如果你是第一次,就死死占住当前的processor,不允许其他goroutine再抢
runtime_procPin()
// 使用CAS操作,先尝试将typ设置为^uintptr(0)这个中间状态
// 如果失败,则证明已经有别的线程抢先完成了赋值操作
// 那它就解除抢占锁,然后重新回到 for 循环第一步
if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
runtime_procUnpin()
continue
}
// 如果设置成功,说明当前goroutine中了jackpot
// 那么就原子性的更新对应的指针,最后解除抢占锁
StorePointer(&vp.data, xp.data)
StorePointer(&vp.typ, xp.typ)
runtime_procUnpin()
return
}
// 如果typ为^uintptr(0)说明第一次写入还没有完成,继续循环等待
if uintptr(typ) == ^uintptr(0) {
continue
}
// 如果要写入的类型和现有的类型不一致,则panic
if typ != xp.typ {
panic("sync/atomic: store of inconsistently typed value into Value")
}
// 更新data
StorePointer(&vp.data, xp.data)
return
}
}
提供了一致类型值的原子加载和存储。 Value 的零值是从 Load 返回 nil。调用 Store 后,不得复制 Value。第一次调用store,就确定value的类型,以后每一次都必须是同样的类型。如果store的值的类型和第一次不一样或者store值是nil那么就会panic。
Load
实现原子读取任意类型的值
// Load returns the value set by the most recent Store.
// It returns nil if there has been no call to Store for this Value.
func (v *Value) Load() (x interface{}) {
// 将*Value指针类型转换为*ifaceWords指针类型
vp := (*ifaceWords)(unsafe.Pointer(v))
// 原子性的获取到v的类型typ的指针
typ := LoadPointer(&vp.typ)
// 如果没有写入或者正在写入,先返回,^uintptr(0)代表过渡状态
if typ == nil || uintptr(typ) == ^uintptr(0) {
return nil
}
// 原子性的获取到v的真正的值data的指针,然后返回
data := LoadPointer(&vp.data)
xp := (*ifaceWords)(unsafe.Pointer(&x))
xp.typ = typ
xp.data = data
return
}
Load 返回最近的 Store 设置的值。如果没有为此值调用 Store,则返回 nil。否则造出一个新的interface{}赋值进去。