atomic

atomic atomic 操作的对象是一个地址,你需要把可寻址的变量的地址作为参数传递给方法,而不是把变量的值传递给方法。
Add

// AddInt32 atomically adds delta to *addr and returns the new value. // AddInt32 以原子方式将 delta 添加到 *addr 并返回新值。 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)). // AddUint32 以原子方式将 delta 添加到 *addr 并返回新值。 //要从 x 中减去一个有符号的正常数值 c,请执行 AddUint32(&x, ^uint32(c-1))。 //特别是,要减1,请执行 AddUint32(&x, ^uint32(0)) // 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)

CAS
// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value. func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value. func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value. // CompareAndSwapInt32 对 int32 值执行比较和交换操作。 func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value. func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value. func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value. func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

比较当前 addr 地址里的值是不是 old,如果不等于 old,就返回 false;如果等于 old,就把此地址的值替换成 new 值,返回 true。
Swap
如果不需要比较旧值,只是比较粗暴地替换的话,就可以使用 Swap 方法,它替换后还可
以返回旧值
// SwapInt32 atomically stores new into *addr and returns the previous *addr value. func SwapInt32(addr *int32, new int32) (old int32)// SwapInt64 atomically stores new into *addr and returns the previous *addr value. // SwapInt32 以原子方式将 new 存储到 *addr 并返回之前的 *addr 值。 func SwapInt64(addr *int64, new int64) (old int64)// SwapUint32 atomically stores new into *addr and returns the previous *addr value. func SwapUint32(addr *uint32, new uint32) (old uint32)// SwapUint64 atomically stores new into *addr and returns the previous *addr value. func SwapUint64(addr *uint64, new uint64) (old uint64)// SwapUintptr atomically stores new into *addr and returns the previous *addr value. func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)// SwapPointer atomically stores new into *addr and returns the previous *addr value. func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

Load
// LoadInt32 atomically loads *addr. // LoadInt32 以原子方式加载 *addr。 func LoadInt32(addr *int32) (val int32)// LoadInt64 atomically loads *addr. func LoadInt64(addr *int64) (val int64)// LoadUint32 atomically loads *addr. func LoadUint32(addr *uint32) (val uint32)// LoadUint64 atomically loads *addr. func LoadUint64(addr *uint64) (val uint64)// LoadUintptr atomically loads *addr. func LoadUintptr(addr *uintptr) (val uintptr)// LoadPointer atomically loads *addr. func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

Store
// StoreInt32 atomically stores val into *addr. // StoreInt32 以原子方式将 val 存储到 *addr。 func StoreInt32(addr *int32, val int32)// StoreInt64 atomically stores val into *addr. func StoreInt64(addr *int64, val int64)// StoreUint32 atomically stores val into *addr. func StoreUint32(addr *uint32, val uint32)// StoreUint64 atomically stores val into *addr. func StoreUint64(addr *uint64, val uint64)// StoreUintptr atomically stores val into *addr. func StoreUintptr(addr *uintptr, val uintptr)// StorePointer atomically stores val into *addr. func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

Value 类型
原子地存取对象类型,但也只能存取,不能 CAS 和 Swap,常常用在配置变更等场景
中。
// Value提供了一致类型值的原子加载和存储。 // Value 的零值从 Load 返回 nil。 // 调用 Store 后,不得复制 Value。 // // 首次使用后不得复制Value。 type Value struct { v any } // ifaceWords is interface{} internal representation. // //ifaceWords 是 interface{} 内部表示。 type ifaceWords struct { typunsafe.Pointer data unsafe.Pointer }

Load
//Load 返回最近的 Store 设置的值。 //如果没有为此value调用 Store,则返回 nil。 // 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() (val any) { vp := (*ifaceWords)(unsafe.Pointer(v)) typ := LoadPointer(&vp.typ) if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) { // First store not yet completed. return nil } data := LoadPointer(&vp.data) vlp := (*ifaceWords)(unsafe.Pointer(&val)) vlp.typ = typ vlp.data = https://www.it610.com/article/data return }

store
var firstStoreInProgress byte// 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(val any) { if val == nil { panic("sync/atomic: store of nil value into Value") } vp := (*ifaceWords)(unsafe.Pointer(v)) vlp := (*ifaceWords)(unsafe.Pointer(&val)) 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. runtime_procPin() if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { runtime_procUnpin() continue } // Complete first store. StorePointer(&vp.data, vlp.data) StorePointer(&vp.typ, vlp.typ) runtime_procUnpin() return } if typ == unsafe.Pointer(&firstStoreInProgress) { // 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. if typ != vlp.typ { panic("sync/atomic: store of inconsistently typed value into Value") } StorePointer(&vp.data, vlp.data) return } }

swap
// Swap stores new into Value and returns the previous value. It returns nil if // the Value is empty. // // All calls to Swap for a given Value must use values of the same concrete // type. Swap of an inconsistent type panics, as does Swap(nil). func (v *Value) Swap(new any) (old any) { if new == nil { panic("sync/atomic: swap of nil value into Value") } vp := (*ifaceWords)(unsafe.Pointer(v)) np := (*ifaceWords)(unsafe.Pointer(&new)) 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. runtime_procPin() if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { runtime_procUnpin() continue } // Complete first store. StorePointer(&vp.data, np.data) StorePointer(&vp.typ, np.typ) runtime_procUnpin() return nil } if typ == unsafe.Pointer(&firstStoreInProgress) { // 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. if typ != np.typ { panic("sync/atomic: swap of inconsistently typed value into Value") } op := (*ifaceWords)(unsafe.Pointer(&old)) op.typ, op.data = https://www.it610.com/article/np.typ, SwapPointer(&vp.data, np.data) return old } }

cas
// CompareAndSwap executes the compare-and-swap operation for the Value. // // All calls to CompareAndSwap for a given Value must use values of the same // concrete type. CompareAndSwap of an inconsistent type panics, as does // CompareAndSwap(old, nil). func (v *Value) CompareAndSwap(old, new any) (swapped bool) { if new == nil { panic("sync/atomic: compare and swap of nil value into Value") } vp := (*ifaceWords)(unsafe.Pointer(v)) np := (*ifaceWords)(unsafe.Pointer(&new)) op := (*ifaceWords)(unsafe.Pointer(&old)) if op.typ != nil && np.typ != op.typ { panic("sync/atomic: compare and swap of inconsistently typed values") } for { typ := LoadPointer(&vp.typ) if typ == nil { if old != nil { return false } // 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. runtime_procPin() if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { runtime_procUnpin() continue } // Complete first store. StorePointer(&vp.data, np.data) StorePointer(&vp.typ, np.typ) runtime_procUnpin() return true } if typ == unsafe.Pointer(&firstStoreInProgress) { // 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. if typ != np.typ { panic("sync/atomic: compare and swap of inconsistently typed value into Value") } // Compare old and current via runtime equality check. // This allows value types to be compared, something // not offered by the package functions. // CompareAndSwapPointer below only ensures vp.data // has not changed since LoadPointer. data := LoadPointer(&vp.data) var i any (*ifaceWords)(unsafe.Pointer(&i)).typ = typ (*ifaceWords)(unsafe.Pointer(&i)).data = https://www.it610.com/article/data if i != old { return false } return CompareAndSwapPointer(&vp.data, data, np.data) } }

type
【atomic】Go1.19新增的类型,使用ayomic类型可以保证安全。新增了Uintptr,支持了对范型的支持。
// Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.package atomicimport "unsafe"// A Bool is an atomic boolean value. // The zero value is false. type Bool struct { _ noCopy v uint32 }// Load atomically loads and returns the value stored in x. func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 }// Store atomically stores val into x. func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) }// Swap atomically stores new into x and returns the previous value. func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 }// CompareAndSwap executes the compare-and-swap operation for the boolean value x. func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) { return CompareAndSwapUint32(&x.v, b32(old), b32(new)) }// b32 returns a uint32 0 or 1 representing b. func b32(b bool) uint32 { if b { return 1 } return 0 }// A Pointer is an atomic pointer of type *T. The zero value is a nil *T. type Pointer[T any] struct { _ noCopy v unsafe.Pointer }// Load atomically loads and returns the value stored in x. func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) }// Store atomically stores val into x. func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) }// Swap atomically stores new into x and returns the previous value. func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) { return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new)) }// An Int32 is an atomic int32. The zero value is zero. type Int32 struct { _ noCopy v int32 }// Load atomically loads and returns the value stored in x. func (x *Int32) Load() int32 { return LoadInt32(&x.v) }// Store atomically stores val into x. func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) }// Swap atomically stores new into x and returns the previous value. func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) { return CompareAndSwapInt32(&x.v, old, new) }// Add atomically adds delta to x and returns the new value. func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }// An Int64 is an atomic int64. The zero value is zero. type Int64 struct { _ noCopy _ align64 v int64 }// Load atomically loads and returns the value stored in x. func (x *Int64) Load() int64 { return LoadInt64(&x.v) }// Store atomically stores val into x. func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) }// Swap atomically stores new into x and returns the previous value. func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) { return CompareAndSwapInt64(&x.v, old, new) }// Add atomically adds delta to x and returns the new value. func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }// An Uint32 is an atomic uint32. The zero value is zero. type Uint32 struct { _ noCopy v uint32 }// Load atomically loads and returns the value stored in x. func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) }// Store atomically stores val into x. func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) }// Swap atomically stores new into x and returns the previous value. func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) { return CompareAndSwapUint32(&x.v, old, new) }// Add atomically adds delta to x and returns the new value. func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }// An Uint64 is an atomic uint64. The zero value is zero. type Uint64 struct { _ noCopy _ align64 v uint64 }// Load atomically loads and returns the value stored in x. func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) }// Store atomically stores val into x. func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) }// Swap atomically stores new into x and returns the previous value. func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) { return CompareAndSwapUint64(&x.v, old, new) }// Add atomically adds delta to x and returns the new value. func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }// An Uintptr is an atomic uintptr. The zero value is zero. type Uintptr struct { _ noCopy v uintptr }// Load atomically loads and returns the value stored in x. func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) }// Store atomically stores val into x. func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) }// Swap atomically stores new into x and returns the previous value. func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) }// CompareAndSwap executes the compare-and-swap operation for x. func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) { return CompareAndSwapUintptr(&x.v, old, new) }// Add atomically adds delta to x and returns the new value. func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }// noCopy may be added to structs which must not be copied // after the first use. // // See https://golang.org/issues/8005#issuecomment-190753527 // for details. // // Note that it must not be embedded, due to the Lock and Unlock methods. type noCopy struct{}// Lock is a no-op used by -copylocks checker from `go vet`. func (*noCopy) Lock(){} func (*noCopy) Unlock() {}// align64 may be added to structs that must be 64-bit aligned. // This struct is recognized by a special case in the compiler // and will not work if copied to any other package. type align64 struct{}

    推荐阅读