Question

I am writing a program that calculates a Riemann sum based on user input. The program will split the function into 1000 rectangles (yes I know I haven't gotten that math in there yet) and sum them up and return the answer. I am using go routines to compute the 1000 rectangles but am getting an

fatal error: all go routines are asleep - deadlock!

What is the correct way to handle multiple go routines? I have been looking around and haven't seen an example that resembles my case? I'm new and want to adhere to standards. Here is my code (it is runnable if you'd like to see what a typical use case of this is - however it does break)

package main

import "fmt"
import "time"

//Data type to hold 'part' of function; ie. "4x^2"
type Pair struct {
    coef, exp int
}

//Calculates the y-value of a 'part' of the function and writes this to the channel
func calc(c *chan float32, p Pair, x float32) {
    val := x

    //Raise our x value to the power, contained in 'p'
    for i := 1; i < p.exp; i++ {

        val = val * val
    }

    //Read existing answer from channel
    ans := <-*c

    //Write new value to the channel
    *c <- float32(ans + (val * float32(p.coef)))
}

var c chan float32    //Channel
var m map[string]Pair //Map to hold function 'parts'

func main() {

    c = make(chan float32, 1001) //Buffered at 1001
    m = make(map[string]Pair)
    var counter int
    var temp_coef, temp_exp int
    var check string
    var up_bound, low_bound float32
    var delta float32

    counter = 1
    check = "default"

    //Loop through as long as we have no more function 'parts'
    for check != "n" {

        fmt.Print("Enter the coefficient for term ", counter, ": ")
        fmt.Scanln(&temp_coef)

        fmt.Print("Enter the exponent for term ", counter, ": ")
        fmt.Scanln(&temp_exp)

        fmt.Print("Do you have more terms to enter (y or n): ")
        fmt.Scanln(&check)

        fmt.Println("")

        //Put data into our map
        m[string(counter)] = Pair{temp_coef, temp_exp}

        counter++
    }

    fmt.Print("Enter the lower bound: ")
    fmt.Scanln(&low_bound)

    fmt.Print("Enter the upper bound: ")
    fmt.Scanln(&up_bound)

    //Calculate the delta; ie. our x delta for the riemann sum
    delta = (float32(up_bound) - float32(low_bound)) / float32(1000)

    //Make our go routines here to add
    for i := low_bound; i < up_bound; i = i + delta {

        //'counter' is indicative of the number of function 'parts' we have
        for j := 1; j < counter; j++ {

            //Go routines made here
            go calc(&c, m[string(j)], i)
        }

    }

    //Wait for the go routines to finish
    time.Sleep(5000 * time.Millisecond)

    //Read the result?
    ans := <-c

    fmt.Print("Answer: ", ans)
}
Was it helpful?

Solution

It dead locks because both the calc() and the main() function reads from the channel before anyone gets to write to it.

So you will end up having every (non-main) go routine blocking at:

ans := <-*c

waiting for someone other go routine to enter a value into the channel. There fore none of them gets to the next line where they actually write to the channel. And the main() routine will block at:

ans := <-c

Everyone is waiting = deadlock

Using buffered channels

Your solution should have the calc() function only writing to the channel, while the main() could read from it in a for-range loop, suming up the values coming from the go-routines.

You will also need to add a way for main() to know when there will be no more values arriving, perhaps by using a sync.WaitGroup (maybe not the best, since main isn't suppose to wait but rather sum things up) or an ordinary counter.

Using shared memory

Sometimes it is not necessarily a channel you need. Having a shared value that you update with the sync/atomic package (atomic add doesn't work on floats) lock with a sync.Mutex works fine too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top