Aranya
Aranya

Reputation: 119

all goroutines are asleep - deadlock! with waitgroup

This is my code, where have I gone wrong?

func main() {
  intChan := make(chan int)
  wg := sync.WaitGroup{}

  for i := 0;i<5;i++{
    wg.Add(1)
    go send(intChan,i,&wg)
  }

  wg.Add(1)
  go get(intChan,&wg)
  wg.Wait()
  time.Sleep(5*time.Second)
  close(intChan)
}

func send(c chan int,index int,wg *sync.WaitGroup){
  defer func() {
    wg.Done()
  }()

  c <- index
}

func get(c chan int,wg *sync.WaitGroup){
  defer func() {
    wg.Done()
  }()

  for i := range c{
    fmt.Printf("%d\n",i)
  }
}

When I run this I get the error fatal error: all goroutines are asleep - deadlock!

Here is error info:

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000120d8)
    C:/Go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc0000120d0)
    C:/Go/src/sync/waitgroup.go:130 +0x6b
main.main()
    F:/go/src/demo/channel.go:94 +0xf9

goroutine 10 [chan receive]:
main.get(0xc00001c120, 0xc0000120d0)
    F:/go/src/demo/channel.go:112 +0xe0
created by main.main
    F:/go/src/demo/channel.go:92 +0xeb

thanks for all,this is my first question.

Upvotes: 3

Views: 773

Answers (2)

Iain Duncan
Iain Duncan

Reputation: 3394

As Andy says in the comments you will only exit the get function when all of the inputs have been received and the channel is closed. As you know there are five things to be received you could have a similar for loop to in the send:

func main() {
    intChan := make(chan int)
    wg := sync.WaitGroup{}

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go send(intChan, i, &wg)
    }

    wg.Add(1)
    go get(intChan, &wg)
    wg.Wait()
    close(intChan)
}

func send(c chan int, index int, wg *sync.WaitGroup) {
    defer func() {
        wg.Done()
    }()

    c <- index
}

func get(c chan int, wg *sync.WaitGroup) {
    defer func() {
        wg.Done()
    }()

    for i := 0; i < 5; i++ {
        input := <- c
        fmt.Printf("%d\n", input)
    }
}

https://play.golang.org/p/CB8HUKPBu2I

If you want to stick with ranging over the channel then you will have to close it when all of the messages have been sent which I would do by adding a second wait group:

func main() {
    intChan := make(chan int)
    allSent := sync.WaitGroup{}

    for i := 0; i < 5; i++ {
        allSent.Add(1)
        go send(intChan, i, &allSent)
    }

    allReceived := sync.WaitGroup{}
    allReceived.Add(1)
    go get(intChan, &allReceived)

    allSent.Wait()
    close(intChan)
    allReceived.Wait()
}

func send(c chan int, index int, wg *sync.WaitGroup) {
    defer func() {
        wg.Done()
    }()

    c <- index
}

func get(c chan int, wg *sync.WaitGroup) {
    defer func() {
        wg.Done()
    }()

    for i := range c {
        fmt.Printf("%d\n", i)
    }
}

https://play.golang.org/p/svFVrBdwmAc

Upvotes: 1

Aranya
Aranya

Reputation: 119

this can work!

func main() {
    intChan := make(chan int)
    wg := sync.WaitGroup{}

    for i := 0;i<5;i++{
        wg.Add(1)
        go send(intChan,i,&wg)
    }

    wg.Add(1)
    go get(intChan,&wg)

    wg.Wait()
    close(intChan)
}

func send(c chan int,index int,wg *sync.WaitGroup){
    defer func() {
        wg.Done()
    }()

    c <- index
}

func get(c chan int,wg *sync.WaitGroup){
    defer func() {
        wg.Done()
    }()

    for {
        select {
            case i := <-c:
                fmt.Printf("%d\n",i)
            default:
                return
        }
    }
}

Upvotes: 0

Related Questions