天天看點

go語言基礎 共享資源競争 互斥鎖sync.Mutex

共享資源競争:

多個goroutine操作同一個共享資料,存在不安全。

i:=1
go func(){  //第一個Goroutine 我們叫他g1
   if i>0{ //①第一次g1執行到這裡的時候,資源被g2搶走
     i--    
     fmt.Pringtln(i)  //輸出i=0
   }
}// ③然後g1搶回資源 執行結束 此時i已經等于0
go func(){  //第二個Goroutine 我們叫他g2
   if i>0{ //②g2執行到這裡的時候又被g1把資源搶走了
     i--  //④由于g1執行完畢 現在就剩下g2了 ,g2順序執行,i--
     fmt.Pringtln(i)//⑤ 此時輸出i已經變成-1了,按理論來說已經不滿足條件了,但是由于判斷已經完成了,是以g2輸出的是-1
   }
}
           

一個共享資料比如i=1,被第一個Goroutien搶到了資源,條件是i>0,判斷成立,下面執行i--,然後列印i,但是在i>0完之後又被第二個Goroutine搶到,同樣執行判斷i>0條件成立同樣的 他也隻是執行了條件判斷,并沒有執行i--和列印,這樣就有兩個滿足條件的Goroutine了,第一個正常完成程式,正常輸出i的值,但是第二個由于資料已經變了,是以輸出的值是錯誤的。為了避免這種情況,我們就要給Goroutine加上互斥鎖,在一個Goroutine通路資料時,别人是不能通路的,隻有等通路完畢開鎖之後,其他人才能來通路。

上鎖:互斥鎖(開,關)

        sync.Mutex

Lock(),UnLock()

我們來舉一個賣票的例子,一共100張票,4個視窗賣,每賣一張,總票數-1,如果在不上鎖的情況下,有可能最後會出現多賣出3張的情況,為了更好的展現賣出的過程,我再裡面加了睡眠。

package main

import (
   "fmt"
   "sync"
   "math/rand"
   "time"
)

//全局變量
var ticket2 = 10 // 100張票
var wg3 sync.WaitGroup

var matex sync.Mutex // 建立鎖頭

func main() {
   /*
   4個goroutine,模拟4個售票口,4個子程式操作同一個共享資料。
    */
   wg3.Add(4)
   go saleticket2s("售票口1") // g1,100
   go saleticket2s("售票口2") // g2,100
   go saleticket2s("售票口3") //g3,100
   go saleticket2s("售票口4") //g4,100
   wg3.Wait()             // main要等待。。。
}

func saleticket2s(name string) {
   rand.Seed(time.Now().UnixNano())
   defer wg3.Done()
   //for i:=1;i<=100;i++{
   // fmt.Println(name,"售出:",i)
   //}

   for { //1, g1 ,g2,g3,g4
       //上鎖, g2
      matex.Lock()
      if ticket2 > 0 { //g1,g3,g2,g4
         //睡眠
         time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
         // g1 ,g3, g2,g4
         fmt.Println(name, "售出:", ticket2)  // 1 , 0, -1 , -2
         ticket2--   //0 , -1 ,-2 , -3
      } else {
         matex.Unlock()//條件不滿足,也要解鎖,結束循環
         fmt.Println("售罄,沒有票了。。")
         break
      }
      matex.Unlock()//解鎖
   }
}