【go源码阅读笔记】 - atomic.Value

828 阅读3分钟

谈一谈原子操作

Go语言最初的sync/atomic支持的数据类型就是几种基本的数据类型,直到Go 1.4版本之后,Go语言新增了Value类型,使得atomic可以支持任意类型数据的读取和存储

提到原子操作就不得不提到一个东西 - 锁,这个在我的历史文章【go源码阅读笔记】 - Sync.Mutex中有提及,感兴趣的读者可以先移步阅读,那么原子操作和锁的区别究竟是什么,首先锁是操作系统层面的,而原子操作是底层硬件提供的支持,在高并发的场景下,原子操作由于可以做到lock free,所以性能会比加锁要好很多

源码解析

在看源代码之前,我们首先需要了解在atomic中结构体的定义

// A Value provides an atomic load and store of a consistently typed value.
// The zero value for a Value returns nil from Load.
// Once Store has been called, a Value must not be copied.
//
// A Value must not be copied after first use.
// Value就是存储和读取的结构体
type Value struct {
   v interface{}
}

// ifaceWords is interface{} internal representation.
// 它的功能就是拆解Value结构题中的v,将它拆解为typ以及data
type ifaceWords struct {
   typ  unsafe.Pointer
   data unsafe.Pointer
}

之后我们来看有关于atomic的两个操作,LoadStore

存储(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{}) {
   // 如果存储元素为空,则直接抛出panic
   if x == nil {
      panic("sync/atomic: store of nil value into Value")
   }
   vp := (*ifaceWords)(unsafe.Pointer(v))    // 通过ifaceWords将旧的值进行分解
   xp := (*ifaceWords)(unsafe.Pointer(&x))   // 通过ifaceWords将新的值进行分解
   for {
      typ := LoadPointer(&vp.typ)            // 获取要存储的元素类型
      if typ == nil {                        // 如果类型为空,也就是第一次存储
         // Attempt to start first store.
         // Disable preemption so that other goroutines can use
         // active spin wait to wait for completion; and so that
         // GC does not see the fake type accidentally.
         // 当前的这个goroutine优先占有CPU,进行下面的操作
         runtime_procPin()                   
         // 这里有一个CAS操作,也就是多个goroutine进行竞争,如果一直没有赋值成功,则当前goroutine
         // 解除CPU的控制权,再与其它的goroutine一起竞争
         if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
            runtime_procUnpin()
            continue
         }
         // Complete first store.
         // 对于类型和数据进行第一次存储
         StorePointer(&vp.data, xp.data)
         StorePointer(&vp.typ, xp.typ)
         // 解除CPU的控制权
         runtime_procUnpin()
         return
      }
      // 如果当前类型还处于中间态,则说明还没有赋值完成,继续循环
      if uintptr(typ) == ^uintptr(0) {
         // First store in progress. Wait.
         // Since we disable preemption around the first store,
         // we can wait with active spinning.
         continue
      }
      // First store completed. Check type and overwrite data.
      // 如果说不是第一次存储,那么当类型与新的要存储的类型不匹配,抛出panic
      if typ != xp.typ {
         panic("sync/atomic: store of inconsistently typed value into Value")
      }
      // 类型一致,则直接修改data的值
      StorePointer(&vp.data, xp.data)
      return
   }
}

读取(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{}) {
   // 获取当前存储元素的类型,如果说类型为空或者类型还处于中间态,则返回空
   vp := (*ifaceWords)(unsafe.Pointer(v))
   typ := LoadPointer(&vp.typ)
   if typ == nil || uintptr(typ) == ^uintptr(0) {
      // First store not yet completed.
      return nil
   }
   // 获取data,并赋值给x
   data := LoadPointer(&vp.data)
   xp := (*ifaceWords)(unsafe.Pointer(&x))
   xp.typ = typ
   xp.data = data
   return
}