所有 goroutine 都处于休眠状态 - 死锁问题

我正在尝试使用两个 goroutine 在同步管理器(1、2、3、4 ...)中打印奇偶数,我很困惑为什么我的代码会导致死锁。请你能帮我理解吗?


package main


import (

    "fmt"

    "sync"

)

var wg sync.WaitGroup


func 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 +0xcf


goroutine 6 [chan send]: main.even(0xc00005e060) /tmp/sandbox505861393/prog.go:26 +0xc5 由 main.main 创建 /tmp/sandbox505861393/prog.go:34 +0x7f


当我更改 goroutine 的顺序时,o/p 开始以奇偶方式打印,我也很难理解这一点。我会很感激你的帮助,谢谢。


慕姐8265434
浏览 82回答 2
2回答

芜湖不芜

首先,你的两个 goroutine 需要从chchannel 接收才能开始工作for i<=10{&nbsp; &nbsp; &nbsp; &nbsp; <-ch // wait until receive&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; &nbsp; &nbsp; i+=2&nbsp; &nbsp; &nbsp; &nbsp; ch <- true&nbsp; &nbsp; }因此,您向通道发送一个值以ch使您的两个 goroutine 工作func main() {&nbsp; &nbsp; //...&nbsp; &nbsp; ch <- true&nbsp; &nbsp; //...}但这不会按预期工作,因为您的两个 goroutine 共享同一个ch通道。在执行时,它们ch <- true中main()只有一个可以接收、开始工作并将值发送回ch通道。之后,两个 goroutine 不断从ch通道接收,开始工作并将值发送回通道换句话说,两个 goroutine 使用chchannel相互发送和接收值for i<=10 {&nbsp; &nbsp; <-ch&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// receive when main() executed at first time, after that receive from another goroutine&nbsp; &nbsp; fmt.Println(i) // start work&nbsp; &nbsp; i+=2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//&nbsp; &nbsp; ch <- true&nbsp; &nbsp; &nbsp;// return back to the channel, another goroutine will receive it}wg.Done()但是问题是当一个goroutine退出时,剩下的goroutine在工作后仍然尝试发送到chchannel,但是没有receiver,这会导致死锁

繁花不似锦

如果通道中没有空间,在通道上发送也会阻塞。如果您在通道中使用缓冲区,则发送可以工作。仅使用 1:ch := make(chan bool, 1)现在您可以发送数据了,它不会因为未满而阻塞 go 例程。如果您再次发送而不读取,那么它将阻止发送调用,因为再次没有空间并且之前的值仍然没有被消耗。关于打印的顺序: goroutine 将首先开始并没有顺序,go lang 规范没有提到多个 goroutine 是否正在从一个通道接收数据,那么首先等待的是否真的首先得到它。因此,如果需要,您需要添加额外的同步来维护订单。这是订购同步的提示。下面是修改后的打印代码,但我更喜欢不同的方法。检查上面链接中的 ping - pong 示例,其中使用了 2 个单独的通道而不是一个。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync")func odd(wg *sync.WaitGroup, ch chan bool) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; i := 1&nbsp; &nbsp; for i <= 10 {&nbsp; &nbsp; &nbsp; &nbsp; <-ch&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; &nbsp; &nbsp; i += 2&nbsp; &nbsp; &nbsp; &nbsp; ch <- true&nbsp; &nbsp; }}func even(wg *sync.WaitGroup, ch chan bool) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; i := 2&nbsp; &nbsp; for i <= 10 {&nbsp; &nbsp; &nbsp; &nbsp; <-ch&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; &nbsp; &nbsp; i += 2&nbsp; &nbsp; &nbsp; &nbsp; ch <- true&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; ch := make(chan bool, 1)&nbsp; &nbsp; defer close(ch)&nbsp; &nbsp; wg.Add(2)&nbsp; &nbsp; go even(&wg, ch)&nbsp; &nbsp; go odd(&wg, ch)&nbsp; &nbsp; ch <- true&nbsp; &nbsp; wg.Wait()}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go