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 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?