原子操作--sync/atomic的用法


golang 通過sync/atomic庫來支持cpu和操作系統級別的原子操作。但是對要操作類型有如下要求

  • int32, int64,uint32, uint64,uintptr,unsafe包中的Pointer。不過,針對unsafe.Pointer類型,該包並未提供進行原子加法操作的函數

sync/atomic 提供的原子操作有

  • 加法(add), 比較並交換(compare and swap, 簡稱CAS),加載(load), 存儲(store),交換(swap)

針對sync/atomic支持的類型,會有注入atomic.AddInt32這樣的函數提供支持

import (
	"fmt"
  "sync/atomic"
)

func main() {
  var a uint32 = 10
  atomic.AddUint32(&a, 1)
  fmt.Println(a)
  // uint32需要一個非負整數,uint32(int32(-1)), 會被編譯器報錯,需要一個中間變量b來繞過
  b := int32(-1)
  atomic.AddUint32(&a, uint32(b))
  fmt.Println(a)
  // ^uint32(n-1), n為要減去的數
  // 整數在計算機以補碼形式存在,這里的異或求出來的補碼與b的補碼相同
  atomic.AddUint32(&a, ^uint32(3-1))
  fmt.Println(a)
}

上面的代碼有幾個點需要注意:

  1. 傳遞給atomic.AddUint32函數的必須是指針類型。同理,unsafe.Pointer也是如此
  2. 對於atomic.AddUint64函數做原子減法,有兩種方法,具體看代碼

sync/atomic 比較並交換操作與交換操作的異同:

  • 比較並交換操作即CAS操作,是有條件的交換操作,只有在條件滿足的情況下才會進行值的交換
func main() {
  var a int32 = 0
  go func() {
    for {
      fmt.Println(a)
       // 當a ==  10,就設置 a=0,並返回ture
      if atomic.CompareAndSwapInt32(&a, 10, 0) {
        fmt.Println("The second number has gone to zero.")
        break
      }
      time.Sleep(time.Millisecond * 500)
      }
  }()
  for {
    a++
    if a >10 {
      break
    }
    time.Sleep(time.Millisecond * 600)
  }
}

sync/automic.Value

  • sync/automic.Value相當於一個容器,可以被用來"原子地"存儲和加載任意的值

atomic.Value使用事項

  • 不用初始化,聲明后即可使用。有兩個指針方法Store和Load
  • atomic.Value類型屬於結構體類型,而結構體屬於值類型,因此對該值的賦值,都會產生新的副本。
  • 不能存儲nil。
  • 第一個存入的值類型,決定了后續atomic.Value可以存入的值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM