0

我想使用setter函数将0-9发送到ch1通道,然后计算机函数将ch1中的数字平方,然后将结果发送到ch2通道。但是,运行此代码时我会感到恐慌。有人能解释为什么会发生这种情况,我完全糊涂了。

package main

import (
    "fmt"
    "sync"
)

func setter(ch1 chan int, wg sync.WaitGroup) {
    for i:= 0; i< 10;i++ {
        fmt.Println("setter:", i)
        ch1 <- i
    }
    close(ch1)
    wg.Done()
}

func computer(ch1 chan int, ch2 chan int, wg sync.WaitGroup) {
    for true {
        tmp, ok := <- ch1
        if !ok {
            fmt.Println("computer: there is no value in ch1")
            break
        }
        fmt.Println("computer:", tmp*tmp)
        ch2 <- tmp*tmp
    }
    close(ch2)
    wg.Done()
}

func main(){
    ch1 := make(chan int,1)
    ch2 := make(chan int,1)
    var wg sync.WaitGroup
    wg.Add(2)
    go setter(ch1, wg)
    go computer(ch1, ch2, wg)

    wg.Wait()
}

像这样的错误:

setter: 0
setter: 1
setter: 2
computer: 0
computer: 1
setter: 3
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000196008)
        /usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc000196000)
        /usr/local/go/src/sync/waitgroup.go:130 +0x65
main.main()
        /Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:50 +0x13b

goroutine 18 [chan send]:
main.setter(0xc000194000, 0x200000000, 0xc000000000)
        /Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:16 +0x107
created by main.main
        /Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:47 +0xdb

goroutine 19 [chan send]:
main.computer(0xc000194000, 0xc000194070, 0x200000000, 0x0)
        /Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:35 +0x11c
created by main.main
        /Users/koujianyuan/Desktop/code/project/go/chan/communication/demo.go:48 +0x12d
4

1 回答 1

1

The reason why there is a deadlock is that you are not reading from the ch2 channel. The ch2 channel block when you try to put the value in it for the second time (the first time it passes because it is a buffered channel of 1). When putting the value in the ch2 channel blocks, it also blocks reading the value from the ch1 channel, so the setter goroutine cannot put values in ch1 anymore.

With both ch1 and ch2 channels blocked, both setter and computer goroutines cannot finish, which causes a deadlock.

Here is a working example. I've added the reader function that read from the ch2 channel.

// The rest of the code is the same except I've changed the functions to use *sync.Waitgroup

func reader(ch chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := range ch {
        fmt.Println("reading from channel", i)
    }
    fmt.Println("reader exiting")
}

func main() {
    ch1 := make(chan int, 1)
    ch2 := make(chan int, 1)
    var wg sync.WaitGroup
    wg.Add(3)
    go reader(ch2, &wg)
    go setter(ch1, &wg)
    go computer(ch1, ch2, &wg)

    wg.Wait()
}
于 2021-12-04T12:01:37.007 回答