Andrei Dascalu
Andrei Dascalu

Reputation: 1177

Issues with chans and waitgroups

While I've seen similar issues, none of the answers found on SO have helped me, but I hope a kind soul with an eagle eye can help me pinpoint the issue here. I know it's not the best use of goroutines but I wanted to do it this way as an exercise, which has obviously failed.

my code

package main

import (
    "fmt"
    "sort"
    "sync"
)

func main() {
    X := []int{1, 2, 3, 4, 0}
    Y := []int{2, 3, 6, 8, 4}

    solution := Solution(X, Y)

    fmt.Println(solution)
}

//Solution solution
func Solution(X []int, Y []int) int {
    size := len(X)

    resultChan := make(chan int)

    results := make(map[int]int)

    ParseDivision(size, X, Y, resultChan)

    for val := range resultChan {
        results[val] = results[val] + 1
    }

    close(resultChan)

    return FindGreatest(results)
}

//Divide divide
func Divide(a int, b int, resultChan chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    result := float64(a) / float64(b)

    resultChan <- int(result * 1000)

}

//FindGreatest find greatest in map
func FindGreatest(myMap map[int]int) int {
    values := make([]int, 0, len(myMap))
    for _, val := range myMap {
        values = append(values, val)
    }

    sort.Ints(values)

    return values[len(values)-1]
}

//ParseDivision int
func ParseDivision(lenth int, X []int, Y []int, resultChan chan<- int) {
    var wg sync.WaitGroup

    wg.Add(lenth)

    for i := 0; i < lenth; i++ {
        go Divide(X[i], Y[i], resultChan, &wg)
    }

    wg.Wait()
}

Result: fatal error: all goroutines are asleep - deadlock!

I am not at all sure why as I've followed a number of examples as well as answers from SO, with respect to passing the waitGroup by reference, as well as using a channel to get the result of the operations performed in goroutines.

Upvotes: 0

Views: 49

Answers (1)

colm.anseo
colm.anseo

Reputation: 22057

Some things to note:

  • the go-routine that writes to a channel should typically close the channel;
  • and following from above, the "reader" go-routine should wait for the channel to close (via range et.c) - i.e. it should never have to close the channel its reading from.
  • since your results channel is unbuffered (buffer size of 0), the main go-routine blocks waiting as the workers try to write, and the main go-routine is not (yet) reading from the results channel (as the pool manager go-routine must complete for this to happen - DEADLOCK!). Solution:
    • ensure the work pool go-routine runs independent of the main (reader) go-routine.

3-line fix: https://play.golang.org/p/9hYuyDgMjGi

Upvotes: 1

Related Questions