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{}赋值进去。

posted @ 2022-03-13 11:07  EthanWell  阅读(575)  评论(0编辑  收藏  举报