亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

所有 goroutine 都處于休眠狀態 - 死鎖問題

所有 goroutine 都處于休眠狀態 - 死鎖問題

Go
慕姐8265434 2022-07-25 10:59:49
我正在嘗試使用兩個 goroutine 在同步管理器(1、2、3、4 ...)中打印奇偶數,我很困惑為什么我的代碼會導致死鎖。請你能幫我理解嗎?package mainimport (    "fmt"    "sync")var wg sync.WaitGroupfunc odd(ch chan bool){    i :=1    for i<=10{        <-ch        fmt.Println(i)        i+=2        ch<-true    }    wg.Done()}func even(ch chan bool){    i :=2    for i<=10{        <-ch        fmt.Println(i)        i+=2        ch <- true    }    wg.Done()}func main() {    ch :=make(chan bool)    wg.Add(2)    go even(ch)    go odd(ch)    ch <- true    wg.Wait()}O/P: 1 2 3 4 5 6 7 8 9 10 致命錯誤:所有 goroutine 都處于休眠狀態 - 死鎖!goroutine 1 [semacquire]: sync.runtime_Semacquire(0x5844a8) /usr/local/go-faketime/src/runtime/sema.go:56 +0x45 sync.(*WaitGroup).Wait(0x5844a0) /usr/local/go- faketime/src/sync/waitgroup.go:130 +0x65 main.main() /tmp/sandbox505861393/prog.go:37 +0xcfgoroutine 6 [chan send]: main.even(0xc00005e060) /tmp/sandbox505861393/prog.go:26 +0xc5 由 main.main 創建 /tmp/sandbox505861393/prog.go:34 +0x7f當我更改 goroutine 的順序時,o/p 開始以奇偶方式打印,我也很難理解這一點。我會很感激你的幫助,謝謝。
查看完整描述

2 回答

?
蕪湖不蕪

TA貢獻1796條經驗 獲得超7個贊

首先,你的兩個 goroutine 需要從chchannel 接收才能開始工作


for i<=10{

        <-ch // wait until receive

        fmt.Println(i)

        i+=2

        ch <- true

    }

因此,您向通道發送一個值以ch使您的兩個 goroutine 工作


func main() {

    //...

    ch <- true

    //...

}

但這不會按預期工作,因為您的兩個 goroutine 共享同一個ch通道。在執行時,它們ch <- true中main()只有一個可以接收、開始工作并將值發送回ch通道。


之后,兩個 goroutine 不斷從ch通道接收,開始工作并將值發送回通道


換句話說,兩個 goroutine 使用chchannel相互發送和接收值


for i<=10 {

    <-ch           // receive when main() executed at first time, after that receive from another goroutine

    fmt.Println(i) // start work

    i+=2           //

    ch <- true     // return back to the channel, another goroutine will receive it

}

wg.Done()

但是問題是當一個goroutine退出時,剩下的goroutine在工作后仍然嘗試發送到chchannel,但是沒有receiver,這會導致死鎖


查看完整回答
反對 回復 2022-07-25
?
繁花不似錦

TA貢獻1851條經驗 獲得超4個贊

如果通道中沒有空間,在通道上發送也會阻塞。如果您在通道中使用緩沖區,則發送可以工作。僅使用 1:


ch := make(chan bool, 1)

現在您可以發送數據了,它不會因為未滿而阻塞 go 例程。如果您再次發送而不讀取,那么它將阻止發送調用,因為再次沒有空間并且之前的值仍然沒有被消耗。


關于打印的順序: goroutine 將首先開始并沒有順序,go lang 規范沒有提到多個 goroutine 是否正在從一個通道接收數據,那么首先等待的是否真的首先得到它。因此,如果需要,您需要添加額外的同步來維護訂單。這是訂購同步的提示。


下面是修改后的打印代碼,但我更喜歡不同的方法。檢查上面鏈接中的 ping - pong 示例,其中使用了 2 個單獨的通道而不是一個。


package main


import (

    "fmt"

    "sync"

)


func odd(wg *sync.WaitGroup, ch chan bool) {

    defer wg.Done()

    i := 1

    for i <= 10 {

        <-ch

        fmt.Println(i)

        i += 2

        ch <- true

    }

}


func even(wg *sync.WaitGroup, ch chan bool) {

    defer wg.Done()

    i := 2

    for i <= 10 {

        <-ch

        fmt.Println(i)

        i += 2

        ch <- true

    }


}


func main() {

    var wg sync.WaitGroup

    ch := make(chan bool, 1)

    defer close(ch)

    wg.Add(2)

    go even(&wg, ch)

    go odd(&wg, ch)

    ch <- true

    wg.Wait()


}


查看完整回答
反對 回復 2022-07-25
  • 2 回答
  • 0 關注
  • 97 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號