all goroutines are asleep - deadlock-Go中協程死鎖詳解

最近學go的channel的時候老是遇到題目中的錯誤:
fatal error: all goroutines are asleep - deadlock!
對問題研究總結後,在此記錄一下

下貼上錯誤代碼:

func testDeadLock(c chan int){
	for{
		fmt.Println(<-c)
	}
}

func main() {
	c :=make(chan int)
	c<-'A'
	go testDeadLock(c)
	time.Sleep(time.Millisecond)
}

看上面main函數中,先開了一個通道channel c,然後馬上對這個c內寫入數據。
然後調協程testDeadLock在c中取數據,結果運行時報錯:
fatal error: all goroutines are asleep - deadlock!

這究竟是咋回事呢?
首先我們這裏通過make(chan int),開闢的通道是一種無緩衝通道,所以當對這個緩衝通道寫的時候,會一直阻塞等到某個協程對這個緩衝通道讀(大家發現沒有這個與典型的生產者消費者有點不一樣,當隊列中“內容”已經滿了,生產者再生往裏放東西纔會阻塞,而這裏我講c<-'A’理解爲生產,他卻是需要等到某個協程讀了再能繼續運行)。
main函數的執行在go語言中本身就是一個協程的執行,所以在執行到c<-'A’的時候,執行main函數的協程將被阻塞,換句話說main函數被阻塞了,此時不能在繼續往下執行了,所以go testDeadLock©這個函數無法執行到了,就無法讀到c中的內容了,所以整個程序阻塞,發生了死鎖。

如何解決這個問題呢?大家想一下,我們阻塞的原因是main函數不能繼續向下執行了,所以go testDeadLock©執行不到,對吧,那我們在main函數中另開一個協程,讓他對c進行寫(對c進行寫的過程不在main函數對應的協程中做),修改後的代碼:

func test(c chan int){
	c<-'A'
}

func testDeadLock(c chan int){
	for{
		fmt.Println(<-c)
	}
}

func main() {
	//chanDemo()
	c :=make(chan int)
	go test(c)
	go testDeadLock(c)
	time.Sleep(time.Millisecond)

}

新增了test函數,在main函數中爲test函數開了協程專門執行,讓對c的寫在test中進行,這樣main函數就能繼續往下執行,去開一個協程執行testDeadLock函數了,這樣一來,雖然剛剛開的test函數中會因爲對c的寫入發生阻塞但並不會影響main函數對應協程的繼續執行,所以之後的testDeadLock馬上將從c中讀出test函數剛剛寫入的內容,這樣一來 test中對c寫入的內容就被testDeadLock順利讀出並打印了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章