原子操作
原子操作是指在程式運行中不能被中斷的操作,原子操作是無鎖的常常是由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 = https://www.cnblogs.com/ourongxin/p/data
return
}
Load 回傳最近的 Store 設定的值,如果沒有為此值呼叫 Store,則回傳 nil,否則造出一個新的interface{}賦值進去,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/442762.html
標籤:Go
上一篇:以QT為例談環境搭建
