Golang學習筆記 原子操作

2021-10-06 18:22:50 字數 2805 閱讀 9487

簡介

型別 增或減add

比較並交換cas

載入load

儲存store

交換swap

原子值sync/atomic.value

執行過程中不能被中斷的操作。在針對某個值的操作過程中,cpu絕不會再去執行其它針對該值的操作,無論這些其他操作是否是原子操作。

對於不能被取位址的值是無法進行原子操作的。

//把乙個int32型別的變數i32的值增大3

newi32 := atomic.addint32(&i32, 3)

//類似函式還有:

//addint64

//adduint32

//adduint64

//adduintptr

第乙個引數是i32的位址。

第二個引數的型別與被運算元必須相同。

adduint32和adduint64函式的第二個引數必須是uint32和畫uint64,因此無法通過傳遞乙個負數來減小被運算元,解決方案:

//把uint32型別的變數的值增加nn(nn表示乙個負整數),或者說減小-nn:

atomic.adduint32(&uint32, ^uint32(-nn-1))

//把uint64型別的變數的值增加nn(nn表示乙個負整數),或者說減小-nn:

atomic.adduint64(&uint64, ^uint64(-nn-1))

//原因:

//乙個負整數的補碼可以通過對它按位(除了符號位)求反碼並加一得到。

//乙個負整數可以由對它的絕對值減1並求補碼後得到數值的二進位制表示法。

//因此表示式uint32(int32(nn))和^uint32(-nn-1)的結果都是一樣的。

//比如-35都為11111111111111111111111111011101

函式會返回新值,但是實際上是賦值給另乙個變數了,i32的值已經在函式返回之前被修改。

unsafe.pointer型別的值無法被加減。

compareandswap為字首的若干函式。

是否等於old,等於的話交換,否則不交換,只有交換了返回值才是true。

與鎖的對比:

鎖是悲觀地覺得會有併發的操作修改被操作值,並需要使用鎖將相關操作放入臨界區加以保護,而cas相當於樂觀地假設原來的值沒有被改變,並一旦確認這個假設的真實性就立即進行值替換。

優勢:可以在不建立互斥量和臨界區的情況下完成併發安全的值替換操作,可以大大減少同步對程式效能的損耗。

劣勢:在被操作值被頻繁變更的情況下,cas的操作並那麼不容易成功,有時候不得不利用for迴圈來進行多次嘗試:

var value int32

func addvalue(delta int32)

}}

cas操作不會讓goroutine阻塞,但是可能使流程的執行暫時停滯,不過這種停滯大多十分短暫。

想要併發安全地更新一些型別時,應優先選擇cas。

原子地讀取某個值(當前計算機中的任何cpu都不會進行其它的針對此值的讀寫操作)。

func addvalue(delta int32) 

}}

上述所有型別(6種)都支援載入操作,包括loadpointer。

原子地寫入某個值(當前計算機中的任何cpu都不會進行其它的針對此值的讀寫操作)。

與cas的區別:不關心原來的值是啥。

與cas區別:不關心被運算元的舊值,但是會把舊的值返回回來。

比cas約束少,比載入功能更強。

該型別有兩個公開的指標方法:load和store。

儲存store:

接收乙個inte***ce{}型別的引數。

限制:不能把nil作為引數傳入;第二次即以後傳入的值必須與之前傳入值的型別一致。違反了這兩個限制會導致乙個執行時恐慌。

讀取load:

返回乙個inte***ce{}型別的結果。

如果還沒有store那麼返回的會是nil。

sync/atomic.value型別的變數一旦被宣告,就不應該被複製到別的地方,雖然不會造成編譯錯誤,但是go vet會報告此類不正確,原因是:對結構體的複製會生成該值的副本,還會生成其中欄位的副本,這樣一來,併發安全保護也就失效惹。甚至向副本儲存值的操作與原值都無關了,當然,sync/atomic.value型別的指標型別的變數不存在這個問題。如果value裡面儲存的值是引用型別,那麼更要注意了。

//以下程式輸出是:[4 5 6]

func main() )

anotherstore(a)

fmt.println(a.load())

}func anotherstore(a atomic.value) )

}//以下程式輸出是:[3 5 6]

func main() )

anotherstore(a)

fmt.println(a.load())

}func anotherstore(a atomic.value) )

anotherstore(a)

fmt.println(a.load())

}func anotherstore(a atomic.value) )

b := a.load().(int)

b[0] = 3

}

可能導致複製的操作如下:

賦值給別人。

作為函式引數傳入。

作為函式結果返回。

作為元素值通過通道傳遞。

《go併發程式設計實戰(第2版)》——郝林

Golang 原子操作與互斥鎖

先來看乙個 package main import fmt runtime sync var counter int32 wg sync.waitgroup func main func addcounter whoami string final counter is 2 首先這個程式是起了兩個 ...

原子性,原子操作

舉個例子 a想要從自己的帳戶中轉1000塊錢到b的帳戶裡。那個從a開始轉帳,到轉帳結束的這乙個過程,稱之為乙個事務。在這個事務裡,要做如下操作 從a的帳戶中減去1000塊錢。如果a的帳戶原來有3000塊錢,現在就變成2000塊錢了。在b的帳戶裡加1000塊錢。如果b的帳戶如果原來有2000塊錢,現在...

Golang學習筆記

如果乙個method的receiver是 t,你可以在乙個t型別的例項變數v上面呼叫這個method,而不需要 v去呼叫這個method 即不需要 v method 如果乙個method的receiver是t,你可以在乙個 t型別的變數p上呼叫這個method,而不需要 p去呼叫這個method。i...