Go 線程同步

線程同步

通常在 Go 語言中有兩種方法可以用來做線程同步

  1. sync.Cond

  2. channel

channel 的很好理解,當我們從一個 channel 中接收數據的時候,如果裏面沒有數據,那我們直接就阻塞在那裏了;在這篇文章中就來看看怎麼使用 sync.Cond 完成同步

sync.Cond

「定義結構體和方法」

type BlueberryInt struct {
 num  int
 lock sync.Mutex
 cond *sync.Cond
}

func NewBlueberryInt() *BlueberryInt {
    // 創建 BlueberryInt 結構體
 var obj BlueberryInt
 obj.num = 0
 obj.cond = sync.NewCond(&obj.lock) // 使用結構體中的 lock 作爲鎖
 return &obj // 返回該結構體的指針
}

func (b *BlueberryInt) IncreaseLocked() {
    // IncreaseLocked 意味着在做加法操作的時候這個函數需要上鎖後才能使用
 b.num++
}

func (b *BlueberryInt) DecreaseLocked() {
    // IncreaseLocked 意味着在做減法操作的時候這個函數需要上鎖後才能使用
 b.num--
}

func (b *BlueberryInt) Signal() {
    // 當完成一件事情後,我們就發送 Signal
 b.cond.Signal()
}

func (b *BlueberryInt) Wait() {
    // 當我們調用 Wait 的時候,我們還不能馬上執行操作
    // 我們需要收到 Signal 後 纔可以繼續執行
 b.cond.Wait()
}

func (b *BlueberryInt) Lock() {
    // 上鎖
 b.lock.Lock()
}

func (b *BlueberryInt) UnLock() {
    // 解鎖
 b.lock.Unlock()
}

「主要邏輯」

我們分別做 1000 次加法和 1000 次減法,但是呢,我們先讓做減法的 goroutine 運行起來,並且使用 Sleep 等待 1 秒鐘,確保它已經跑起來了;如果我們沒有使用 sync.Cond 的話,這時候減法操作拿到鎖之後就可以直接完成 1000 次的減法了,但是我們調用了 num.Wait() 來等待信號

爲什麼我們在做減法的 goroutine 中已經使用了 num.Lock 之後,在做加法的 goroutine 中還能夠獲得鎖呢?這就是因爲我們在 NewBlueberryInt 中的這行代碼 obj.cond = sync.NewCond(&obj.lock) ,但我們調用 Wait 的時候,它會先釋放我們傳入的那把鎖並且阻塞在那裏,然後等待信號的到來,當它收到信號之後重新獲取那把鎖然後再繼續執行操作

func main() {
 // 做了加法才能做減法
 b := NewBlueberryInt()
 fmt.Printf("the num b is %d \n", b.num)

 // 做減法 1000 次
 go func(num *BlueberryInt) {
  num.Lock()
  num.Wait() // 等待信號
  for i := 0; i < 1000; i++ {
   num.DecreaseLocked()
  }
  num.UnLock()
 }(b)

 time.Sleep(time.Second)

 // 做加法 1000 次
 go func(num *BlueberryInt) {
  num.Lock()
  for i := 0; i < 1000; i++ {
   num.IncreaseLocked()
  }
  num.Signal() // 發送信號
  num.UnLock() // 一定要記得釋放鎖,不然做減法的 goroutine 那裏就永遠走不動了
 }(b)

 time.Sleep(time.Second)

 b.Lock()
 fmt.Printf("the num b is %d \n", b.num)
 b.UnLock()
}

最後的輸出結果就是這樣的:

the num b is 0 
the num b is 0

我是:藍莓,**做個酷的人,過完一生 :)
**微信:點擊我的公衆號底部聯繫我按鈕
強烈推薦加入我的星球 ~
知識星球:酷酷的算法(免費)
星球號:58799376
GitHub:https://github.com/teenager-lijh
小紅書:2133670884
B 站:公衆號同名

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/vk5weMM3kFsX5H6C10GSjQ