go 原子操作 atomic的使用

2021-09-23 10:39:39 字數 1843 閱讀 9096

go語言提供的原子操作都是非侵入式的,它們由標準庫**包sync/atomic中的眾多函式代表。

我們呼叫sync/atomic中的幾個函式可以對幾種簡單的型別進行原子操作。這些型別包括int32,int64,uint32,uint64,uintptr,unsafe.pointer,共6個。這些函式的原子操作共有5種:增或減,比較並交換、載入、儲存和交換它們提供了不同的功能,切使用的場景也有區別。

顧名思義,原子增或減即可實現對被操作值的增大或減少。因此該操作只能運算元值型別。

被用於進行增或減的原子操作都是以「add」為字首,並後面跟針對具體型別的名稱。

//方法原始碼

func adduint32(addr *uint32, delta uint32) (new uint32)

增加

示例:(在原來的基礎上加n)

atomic.adduint32(&addr,n)

示例:(在原來的基礎上加n(n為負數))

atomic.adduint32(*addr,uint32(int32(n)))

//或atomic.adduint32(&addr,^uint32(-n-1))

比較並交換----compare and swap 簡稱cas

他是假設被操作的值未曾被改變(即與舊值相等),並一旦確定這個假設的真實性就立即進行值替換

如果想安全的併發一些型別的值,我們總是應該優先使用cas

//方法原始碼
示例:(如果addr和old相同,就用new代替addr)

ok:=atomic.compareandswapint32(&addr,old,new)
如果乙個寫操作未完成,有乙個讀操作就已經發生了,這樣讀操作使很糟糕的。

為了原子的讀取某個值sync/atomic**包同樣為我們提供了一系列的函式。這些函式都以"load"為字首,意為載入。

//方法原始碼

func loadint32(addr *int32) (val int32)

示例

fun addvalue(delta int32)

}}

與讀操作對應的是寫入操作,sync/atomic也提供了與原子的值載入函式相對應的原子的值儲存函式。這些函式的名稱均以「store」為字首

在原子的儲存某個值的過程中,任何cpu都不會進行針對進行同乙個值的讀或寫操作。如果我們把所有針對此值的寫操作都改為原子操作,那麼就不會出現針對此值的讀操作讀操作因被併發的進行而讀到修改了一半的情況。

原子操作總會成功,因為他不必關心被操作值的舊值是什麼。

//方法原始碼

func storeint32(addr *int32, val int32)

示例

atomic.storeint32(被操作值的指標,新值)

atomic.storeint32(&value,newaddr)

原子交換操作,這類函式的名稱都以「swap」為字首。

與cas不同,交換操作直接賦予新值,不管舊值。

會返回舊值

//方法原始碼

func swapint32(addr *int32, new int32) (old int32)

示例

atomic.swapint32(被操作值的指標,新值)(返回舊值)

oldval:=atomic.storeint32(&value,newaddr)

原子操作 atomic

所謂的原子操作,取的就是 原子是最小的 不可分割的最小個體 的意義,它表示在多個執行緒訪問同乙個全域性資源的時候,能夠確保所有其他的執行緒都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的執行緒對這個資源進行訪問。這有點類似互斥物件對共享資源的訪問的保護,但是原子操作更加接近底層,因...

原子操作atomic

c 中有atomic類和atomic flag兩個類,其中atomic類用於定義乙個原子操作,atomic flag定義一些與原子操作相關的函式 如下操作 atomic原子操作.cpp 定義控制台應用程式的入口點。一般的操作如上,我們開啟兩個執行緒,定義乙個全域性變數n,定義乙個執行緒函式,想要執行...

atomic原子操作

atomic原子操作在一些場景下,相比於其他的併發原語,效能更優 舉個例子 假設你想在程式中使用乙個標誌 flag,比如乙個 bool 型別的變數 來標識乙個定時任務是否已經啟動執行了,你會怎麼做呢?我們先來看看加鎖的方法。如果使用 mutex 和 rwmutex,在讀取和設定這個標誌的時候加鎖,是...