duanjiaoxi4928 2014-05-08 00:12
浏览 38
已采纳

Go线程死锁错误-使用go例程的正确方法是什么?

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)
}
  • 写回答

1条回答 默认 最新

  • doulian4762 2014-05-08 00:21
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计