在本文中,我們將分析「死鎖」背後的原因!下列程式碼片段涉及Go 通道的死鎖情況所造成的錯誤:
package main import ( "fmt" "sync" ) func push(c chan int, wg sync.WaitGroup) { for i := 0; i < 5; i++ { c <- i } wg.Done() } func pull(c chan int, wg sync.WaitGroup) { for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done() } func main() { var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, wg) go pull(c, wg) wg.Wait() }
執行此程式碼時,我們遇到以下錯誤:
throw: all goroutines are asleep - deadlock!
發生死鎖是因為結構(例如此程式碼中的sync.WaitGroup)是按值傳遞而不是按引用傳遞。這意味著當我們將 WaitGroup 傳遞給我們的函數(推和拉)時,我們實際上傳遞的是 WaitGroup 的副本而不是原始物件。
因此,每個函數都在自己的副本上工作WaitGroup 的副本,當它們呼叫 wg.Done() 時,它們會遞減自己的副本。這不會更新我們的主協程正在等待的原始 WaitGroup,從而導致死鎖。
要解決這個問題,我們需要傳遞指標到 WaitGroup 而不是值。這將確保推送和拉取函數都在 WaitGroup 的同一個實例上運作,並且它們對 wg.Done() 的呼叫將影響原始物件。
這是程式碼的更正版本:
package main import ( "fmt" "sync" ) func push(c chan int, wg *sync.WaitGroup) { for i := 0; i < 5; i++ { c <- i } wg.Done() } func pull(c chan int, wg *sync.WaitGroup) { for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done() } func main() { var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, &wg) go pull(c, &wg) wg.Wait() }
透過進行此更改,我們現在將指向WaitGroup 的指標傳遞給我們的函數,確保它們都在同一物件上工作並正確更新其狀態。這消除了死鎖情況,讓我們的程式能夠無錯誤地運作。
以上是使用sync.WaitGroup時如何修復Go頻道中的死鎖錯誤?的詳細內容。更多資訊請關注PHP中文網其他相關文章!