所有戈鲁丁都睡着了 - 死锁问题

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


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.(*等待组)。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 开始以奇偶的方式打印,我也很难理解这一点。我将不胜感激你的帮助,谢谢。


慕莱坞森
浏览 108回答 2
2回答

小唯快跑啊

如果通道中没有空间,则在通道上发送也会阻止。如果在通道中使用缓冲区,则发送可以工作。仅使用 1:ch&nbsp;:=&nbsp;make(chan&nbsp;bool,&nbsp;1)现在,您可以发送数据,并且它不会阻止go例程,因为它没有满。如果您在没有读取的情况下再次发送,那么它将阻止发送调用,因为再次没有空间并且仍然没有消耗以前的值。关于打印的顺序:没有顺序,其中go例程将首先开始,go lang规范没有提到多个go例程是否从一个通道接收数据,那么首先等待的人是否真的首先获得它。因此,如果需要,您需要添加其他同步以维护顺序。以下是订购同步的提示。下面是打印的修改代码,但我更喜欢不同的方法。检查上面链接中的乒乓球示例,其中使用了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()}

犯罪嫌疑人X

首先,您的两个 Goroutine 需要从通道接收才能开始工作chfor 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; }因此,您将值发送到通道,以使两个 goroutine 工作chfunc main() {&nbsp; &nbsp; //...&nbsp; &nbsp; ch <- true&nbsp; &nbsp; //...}但这不会像预期的那样工作,因为你们的两个goroutine共享同一个频道。执行时,只有一个可以接收、开始工作并将值发送回通道。chch <- truemain()ch之后,两个 goroutine 不断从通道接收,开始工作并将值发送回通道ch换句话说,两个 goroutine 通过使用通道相互发送和接收值chfor 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仍然试图在下班后发送到通道,但没有接收器,这会导致死锁ch
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go