sync
atomic
asm.s
#include "textflag.h"
TEXT ·SwapInt32(SB),NOSPLIT,$0
JMP runtime∕internal∕atomic·Xchg(SB)
这段代码是的作用是用于交换两个32位整数的值。
具体来说,这段代码定义了一个名为SwapInt32
的函数,它是一个不需要栈分裂(NOSPLIT)的函数,并且它没有本地变量($0)。该函数通过跳转到runtime∕internal∕atomic·Xchg(SB)
函数来实现整数交换操作。
value.go
// LoadPointer atomically loads *addr.
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
// StorePointer atomically stores val into *addr.
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
// SwapPointer atomically stores new into *addr and returns the previous *addr value.
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
Value提供一致类型化值的原子加载和存储
type Value struct {
v any
}
ifaceWords 是 interface{} 的底层结构体。由类型指针和数据指针,两个指针构成,所以interface{}的修改并不是原子的。
type ifaceWords struct {
typ unsafe.Pointer
data unsafe.Pointer
}
Load 返回由最新Store()设置的值。如果还没有为此值调用 Store(),则返回 nil。
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 = data
return
}
首先,将Value
类型的指针v
转换为ifaceWords
类型的指针vp
,ifaceWords
用于存储接口类型和实际的数据值。unsafe.Pointer
函数用于将指针转换为通用的指针类型。
接下来,通过LoadPointer
函数加载vp.typ
字段的值,并将其赋给typ
变量。如果typ
的值为nil
或者等于unsafe.Pointer(&firstStoreInProgress)
,说明第一个存储操作还未完成,直接返回nil
表示读取失败。
如果typ
的值不为nil
且不等于unsafe.Pointer(&firstStoreInProgress)
,则说明第一个存储操作已经完成。继续通过LoadPointer
函数加载vp.data
字段的值,并将其赋给data
变量。
然后,将val
转换为ifaceWords
类型的指针vlp
,并将typ
和data
赋值给vlp.typ
和vlp.data
字段,最后将val
返回。这样就完成了对Value
类型的值的读取操作。
Store实现了对Value
类型的存储操作,保证了原子性和类型正确性。
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
}
}
首先,判断传入的值val
是否为nil
,如果是则抛出异常,不能将nil
值存储到Value
类型中。
然后,将Value
类型的指针v
和val
转换为ifaceWords
类型的指针vp
和vlp
,并通过LoadPointer
函数加载vp.typ
字段的值,赋给typ
变量。
如果typ
的值为nil
,说明当前还没有进行过存储操作,因此尝试开始第一个存储操作。通过调用runtime_procPin
函数禁用抢占,让其他goroutine可以通过主动自旋等待存储操作的完成。然后通过CompareAndSwapPointer
函数将vp.typ
字段的值从nil
修改为unsafe.Pointer(&firstStoreInProgress)
,如果修改失败则继续自旋等待。如果修改成功,则表示第一个存储操作已经开始,继续通过StorePointer
函数将vp.data
和vp.typ
字段的值设置为vlp.data
和vlp.typ
的值,完成第一个存储操作,并通过runtime_procUnpin
函数解除抢占禁用。
如果typ
的值为unsafe.Pointer(&firstStoreInProgress)
,说明第一个存储操作还在进行中,继续自旋等待。
如果typ
的值不为nil
且不等于unsafe.Pointer(&firstStoreInProgress)
,则说明已经完成了第一个存储操作。此时检查typ
的值是否与vlp.typ
相等,如果不相等则抛出异常。否则,通过StorePointer
函数将vp.data
的值设置为vlp.data
的值,完成存储操作。
Swap 用于原子地进行交换值
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 = np.typ, SwapPointer(&vp.data, np.data)
return old
}
}
这段代码实现了 Value
类型的 Swap
方法,用于原子地交换值。该方法首先检查 new
参数是否为 nil
,如果是,则抛出 panic 异常。然后通过将 Value
类型转换为 ifaceWords
结构体的指针来访问其内部字段。接下来,循环检查 typ
字段是否为 nil
。如果是 nil
,则尝试开始第一个存储操作,并将 Value
类型设置为一个特殊的指针 &firstStoreInProgress
。在这种情况下,为了避免其他 goroutine 干扰存储操作,该方法会禁用抢占,并采用主动自旋的方式等待存储操作完成。一旦第一个存储操作完成,Swap
方法会将 old
参数的值设置为原来 Value
类型的值,然后再用新值替换它。如果 typ
字段不为 nil
,则检查它的值是否与新值的类型相同,如果不同,则抛出 panic 异常。如果类型匹配,则使用 SwapPointer
方法原子地交换数据字段的值,并将旧值返回。由于存在并发写入的情况,该方法会在必要时通过自旋等待其他 goroutine 完成其操作,而不会被阻塞。
CompareAndSwap方法用于比较并交换一个 Value
类型的值。
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 = data
if i != old {
return false
}
return CompareAndSwapPointer(&vp.data, data, np.data)
}
}
参数 old
和 new
分别表示原始值和期望更新的新值。如果 old
的类型与 Value
的类型不匹配,方法将 panic。该方法使用一个 for
循环来执行操作,以确保操作完成。
在循环开始时,将获取 Value
类型的类型信息。如果值为 nil
,则表示 Value
目前没有存储任何值。在这种情况下,如果 old
的值不为 nil
,则表示不需要执行交换操作,方法将返回 false。否则,方法将尝试执行第一次存储操作。在此期间,将禁用抢占,以便其他 goroutine 可以使用主动自旋等待完成。完成第一次存储后,将启用抢占并返回 true。
如果 Value
的类型信息不为 nil
,则将检查其类型信息是否与 new
的类型信息匹配。如果不匹配,将 panic。
接下来,方法将使用 LoadPointer
函数获取 Value
存储的数据指针,并将其与 old
的值进行比较。如果这两个值不相等,则说明当前 Value
的值与 old
的值不匹配,因此方法将返回 false。否则,该方法将使用 CompareAndSwapPointer
函数来尝试交换 Value
的数据指针和 new
的数据指针。如果成功,该方法将返回 true,否则将继续循环。