为了账号安全,请及时绑定邮箱和手机立即绑定

致命错误:所有 goroutine 都在睡觉 - 死锁!将 WaitGroup

致命错误:所有 goroutine 都在睡觉 - 死锁!将 WaitGroup

Go
函数式编程 2023-07-31 10:51:14
go版本: go1.12.5 linux/amd64我试图理解 Go 中的 nil 通道。package mainimport (    "fmt"    "sync")func main() {    ch := make(chan int)    ch2 := make(chan int)    wg := sync.WaitGroup{}    wg.Add(1)    go func(c1 chan int, c2 chan int, w *sync.WaitGroup) {        for c1 != nil || c2 != nil {            fmt.Println("in for")            fmt.Println(c1, c2)            select {            case v, ok := <-c1:                if !ok {                    c1 = nil                    fmt.Println("c1 closed")                } else {                    fmt.Println(v, " recieved c1")                }            case v, ok := <-c2:                if !ok {                    c2 = nil                } else {                    fmt.Println(v, " recieved c2")                }            }        }        fmt.Println("called wg.Done")        wg.Done()    }(ch, ch2, &wg)    for i := 0; i < 4; i++ {        if i%2 == 0 {            ch <- i        } else {            ch2 <- i        }    }    close(ch)    wg.Wait()}并在标准输出上收到此输出:in for0xc000084060 0xc0000840c00  recieved c1in for0xc000084060 0xc0000840c01  recieved c2in for0xc000084060 0xc0000840c02  recieved c1in for0xc000084060 0xc0000840c03  recieved c2in for0xc000084060 0xc0000840c0c1 closedin for<nil> 0xc0000840c0fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0xc00009a018)        /usr/local/go/src/runtime/sema.go:56 +0x39sync.(*WaitGroup).Wait(0xc00009a010)        /usr/local/go/src/sync/waitgroup.go:130 +0x65main.main()        /home/ayush/projects/gojects/src/go-practice/nil-channels/main.go:44 +0x155goroutine 18 [select]:main.main.func1(0xc00009a010, 0xc000084060, 0xc0000840c0, 0xc00009a010)        /home/ayush/projects/gojects/src/go-practice/nil-channels/main.go:17 +0x1e5created by main.main        /home/ayush/projects/gojects/src/go-practice/nil-channels/main.go:13 +0xceexit status 2但根据代码和日志,wg.Done()从未被调用过,这意味着 goroutine 仍然存在。谁能帮我理解这里发生了什么?
查看完整描述

2 回答

?
慕沐林林

TA贡献2016条经验 获得超9个赞

你只有靠近ch,没有ch2。当ch关闭时,goroutine 设置c1为 nil,但c2仍然不是 nil,因此select等待从 接收c2,而主 goroutine 等待wg.Done(),因此两个 goroutine 都处于睡眠状态。



查看完整回答
反对 回复 2023-07-31
?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

这是因为你没有关闭而发生的ch2。选择块仍在等待ch2。


工作代码:


package main


import (

    "fmt"

    "sync"

)


func main() {

    ch := make(chan int)

    ch2 := make(chan int)

    wg := sync.WaitGroup{}

    wg.Add(1)


    go func(c1 chan int, c2 chan int, w *sync.WaitGroup) {

        for c1 != nil || c2 != nil {


            select {

            case v, ok := <-c1:

                if !ok {

                    c1 = nil

                    fmt.Println("c1 closed")

                } else {

                    fmt.Println(v, " recieved c1")

                }

            case v, ok := <-c2:

                if !ok {

                    c2 = nil

                } else {

                    fmt.Println(v, " recieved c2")

                }

            }

        }


        fmt.Println("called wg.Done")

        wg.Done()

    }(ch, ch2, &wg)


    for i := 0; i < 4; i++ {

        if i%2 == 0 {

            ch <- i

            fmt.Println("sending to c1 ", i)

        } else {

            ch2 <- i

            fmt.Println("sending to c2 ", i)

        }

    }

    close(ch)

    close(ch2)

    wg.Wait()

}



查看完整回答
反对 回复 2023-07-31
  • 2 回答
  • 0 关注
  • 129 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信