併發技術5:死鎖問題
阿新 • • 發佈:2018-12-21
1. 同一個goroutine中,使用同一個 channel 讀寫
package main
func main(){
ch:=make(chan int) //這就是在main程裡面發生的死鎖情況
ch<-6 // 這裡會發生一直阻塞的情況,執行不到下面一句
<-ch
}
這是最簡單的死鎖情況
看執行結果
1. 2個 以上的go程中, 使用同一個 channel 通訊。 讀寫channel 先於 go程建立。
package main func main(){ ch:=make(chan int) ch<-666 //這裡一直阻塞,執行不到下面 go func (){ <-ch //這裡雖然建立了子go程用來讀出資料,但是上面會一直阻塞執行不到下面 }() }
這裡如果想不成為死鎖那匿名函式go程就要放到ch<-666這條語句前面
3. 2個以上的go程中,使用多個 channel 通訊。 A go 程 獲取channel 1 的同時,嘗試使用channel 2, 同一時刻,B go 程 獲取channel 2 的同時,嘗試使用channel 1
package main func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { //匿名子go程 for { select { //這裡互相等對方造成死鎖 case <-ch1: //這裡ch1有資料讀出才會執行下一句 ch2 <- 777 } } }() for { //主go程 select { case <-ch2 : //這裡ch2有資料讀出才會執行下一句 ch1 <- 999 } } }
第三種是互相等對方造成死鎖
4.注意讀寫模式的鎖定不要互相阻塞
- 隱形死鎖:系統的兩個或多個任務之間互相阻塞對方,形成事實上的死鎖局面,然而只要有可執行的協程,編譯器就不會顯式地報死鎖錯誤——這就是隱形死鎖;
- 開發中真正可怕的不是顯式的死鎖,而是隱形死鎖;
func main() { var rwm09 sync.RWMutex ch := make(chan int, 0) //子協程負責寫入 go func() { //連鎖都搶不到555... rwm09.Lock() ch <- 123 rwm09.Unlock() }() go func() { //本協程負責讀出 rwm09.RLock() //只要讀不到內容就永遠阻塞 x := <- ch fmt.Println("讀到",x) rwm09.RUnlock() }() for { //通知垃圾回收器來清理垃圾(即使不叫也會定時清理) runtime.GC() } }
清華團隊帶你實戰區塊鏈開發
掃碼獲取海量視訊及原始碼 QQ群:721929980