golang sync/atomic
原子操作之sync/atomic
在sync.Once中我們通過查看源碼看到過有使用atomic來實(shí)現(xiàn)一個Once只執(zhí)行一次的操作,我們今天就來著重看一下關(guān)于原子操作的atomic
sync.Once :https://blog.csdn.net/weixin_40165163/article/details/90246434
首先我們需要新了解它的作用:
對于并發(fā)操作而言,原子操作是個非常現(xiàn)實(shí)的問題。典型的就是i++的問題。 當(dāng)兩個CPU同時對內(nèi)存中的i進(jìn)行讀取,然后把加一之后的值放入內(nèi)存中,可能兩次i++的結(jié)果,這個i只增加了一次。 如何保證多CPU對同一塊內(nèi)存的操作是原子的。 golang中sync/atomic就是做這個使用的。
關(guān)于實(shí)現(xiàn)的部分:
具體的原子操作在不同的操作系統(tǒng)中實(shí)現(xiàn)是不同的。比如在Intel的CPU架構(gòu)機(jī)器上,主要是使用總線鎖的方式實(shí)現(xiàn)的。 大致的意思就是當(dāng)一個CPU需要操作一個內(nèi)存塊的時候,向總線發(fā)送一個LOCK信號,所有CPU收到這個信號后就不對這個內(nèi)存塊進(jìn)行操作了。 等待操作的CPU執(zhí)行完操作后,發(fā)送UNLOCK信號,才結(jié)束。** 在AMD的CPU架構(gòu)機(jī)器上就是使用MESI一致性協(xié)議的方式來保證原子操作。** 所以我們在看atomic源碼的時候是看不到具體的實(shí)現(xiàn)的。
與Mutex相比:
- 如果我們善用原子操作,它會比Mutex更為高效。
- 比Mutex更加靈活,通過了解鎖我們知道Mutex會將當(dāng)被限制在當(dāng)前goroutine中,只有在Unlock后其他goroutine才有可能獲取資源。
- 比Mutex更底層。
Mutex:https://blog.csdn.net/weixin_40165163/article/details/90116821
交換值的原子操作:
//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. 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)CAS
判斷內(nèi)存中的某個值是否等于old值,如果是的話,則賦new值給這塊內(nèi)存。CAS是一個方法,并不局限在CPU原子操作中。 CAS比互斥鎖樂觀,但是也就代表CAS是有賦值不成功的時候,調(diào)用CAS的那一方就需要處理賦值不成功的后續(xù)行為了。?
// 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. 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)原子加操作:
// 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)加操作也可以完成減的操作?在計(jì)算機(jī)中只有加實(shí)際上 加可以實(shí)現(xiàn)任何方式的計(jì)算
atomic.AddUint32函數(shù):
atomic.AddUint32(&ui32, ^uint32(-NN-1))?
對于uint64類型的值來說也是這樣。調(diào)用表達(dá)式
atomic.AddUint64(&ui64, ^uint64(-NN-1))原子讀取操作:?
// LoadInt32 atomically loads *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)?原子寫操作:
// StoreInt32 atomically stores val into *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)?golang源碼的注釋是比較給力的,通過源碼我們就可以知道應(yīng)該使用那種方式來達(dá)到我們的目的,所以這里不做過多介紹了。
參考資料:https://golang.org/pkg/sync/atomic/
總結(jié)
以上是生活随笔為你收集整理的golang sync/atomic的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hibernate源码解析
- 下一篇: 2022年河北省高职单招(职业倾向性)考