簡介
型別 增或減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...