JianYuan Kou
JianYuan Kou

Reputation: 39

why is there deadlock when using wait group and channel in go?

I wanna use setter function to send 0-9 into ch1 channel ,and computer function square the number from ch1, then send the result into ch2 channel . however, i get panic when running this code. would anybody explain why this situation happened, i totally confused.

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()
}

the error like this :

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

Upvotes: 0

Views: 378

Answers (1)

Emin Laletovic
Emin Laletovic

Reputation: 4324

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()
}

Upvotes: 1

Related Questions