七叶笔记 » golang编程 » golang系列:atomic 原子操作

golang系列:atomic 原子操作

原子操作 是在执行中不能被中断的操作,通常由CPU芯片级能力来保证,并由操作系统提供调用,golang基于操作系统的能力,也提供了基于原子操作的支持。

原子操作与临界区的区别

原子操作是能保证执行期间连续的,不会被中断

临界区只能保证访问共享数据是按顺序访问的,但不保证访问期间不会被切换context

golang提供的原子操作

atomic 包有几种原子操作,主要是 Add、CompareAndSwap、Load、Store、Swap,类型主要是为 int32 int64 uint32 uint64 uintptr unsafe.Pointer Value。

 func AddInt32(addr *int32, delta int32) (new int32)
func AddInt64(addr *int64, delta int64) (new int64)
func AddUint32(addr *uint32, delta uint32) (new uint32)
func AddUint64(addr *uint64, delta uint64) (new uint64)
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (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 LoadInt32(addr *int32) (val int32)
func LoadInt64(addr *int64) (val int64)
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
func LoadUint32(addr *uint32) (val uint32)
func LoadUint64(addr *uint64) (val uint64)
func LoadUintptr(addr *uintptr) (val uintptr)
func StoreInt32(addr *int32, val int32)
func StoreInt64(addr *int64, val int64)
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
func StoreUint32(addr *uint32, val uint32)
func StoreUint64(addr *uint64, val uint64)
func StoreUintptr(addr *uintptr, val uintptr)
func SwapInt32(addr *int32, new int32) (old int32)
func SwapInt64(addr *int64, new int64) (old int64)
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
func SwapUint32(addr *uint32, new uint32) (old uint32)
func SwapUint64(addr *uint64, new uint64) (old uint64)
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
type Value
func (v *Value) CompareAndSwap(old, new any) (swapped bool)
func (v *Value) Load() (val any)
func (v *Value) Store(val any)
func (v *Value) Swap(new any) (old any)  
  • 原子操作函数的第一个参数都是传变量地址的,因为原子函数需要改变变量的值
  • 原子操作函数可以给add传入负数来做减法,计算机内部都是补码加法,没有减法
  • CompareAndSwap 是带条件的swap,只有符合条件才能swap

atomic.Value

  • 支持原子性的load/store任意值
  • 一旦开始存一个值那么后续所有值的类型必须和第一个值得类型一致
  • 不支持nil
  • 不能copy,copy后就是另一个Value了
  • 不建议存储引用类型的值
  • 建议是私有变量,不要对外公开,更新需要严格检查条件

atomic.Value vs sync.Mutex

atomic.Value 简单、性能好,无死锁问题,但限制多

sync.Mutex 是最通用的保护方案

优先选择atomic.Value

相关文章