登录
首页 >  Golang >  Go问答

所有goroutine都陷入死锁,出现致命错误

来源:stackoverflow

时间:2024-03-14 09:33:28 299浏览 收藏

对于一个Golang开发者来说,牢固扎实的基础是十分重要的,golang学习网就来带大家一点点的掌握基础知识点。今天本篇文章带大家了解《所有goroutine都陷入死锁,出现致命错误》,主要介绍了,希望对大家的知识积累有所帮助,快点收藏起来吧,否则需要时就找不到了!

问题内容

我在函数 findpathconcurently 中收到此错误。由于我是 go 新手,我试图理解它,但无法提供任何帮助,我将不胜感激。我正在尝试解决为迷宫求解器编写代码的问题。 node 只是一个带有 next 和 value 的结构。

func FindExitConcurrently(root []*Node, paths chan []string, path []string, index int) {
    for _, node := range root {
        if node.Value == consts.SUCCESS {
            paths <- path
            return
        }
        if node.Next == nil {
            path = nil
            return
        }
        path = append(path, node.Value)
        index++
        FindExitConcurrently(node.Next, paths, path, index)
        path = nil
        index--
    }
    if index == 0 {
        close(paths)
    }
}

func FindPathConcurrently(parentNode *Node) {
    var pathChannels []chan []string
    for key, value := range parentNode.Next {
        pathChannels = append(pathChannels, make(chan []string))
        go FindExitConcurrently(value.Next, pathChannels[key], nil, 0)
    }
    cases := make([]reflect.SelectCase, len(pathChannels))
    for i, ch := range pathChannels {
        cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
    }

    remaining := len(cases)
    for remaining > 0 {
        chosen, value, ok := reflect.Select(cases)
        if !ok {
            // The chosen channel has been closed, so zero out the channel to disable the case
            cases[chosen].Chan = reflect.ValueOf(nil)
            remaining -= 1
            continue
        }
        //fmt.Printf("Read from channel %#v and received %s\n", pathChannels[chosen], value.String())
        fmt.Println(value)
    }
}


正确答案


您没有始终如一地关闭通道,从而造成了僵局。考虑从 goroutine 引出的所有路径(提示:其中一些路径很早 return ,因此跳过 close(...) 调用)。

要解决并发问题,请使用您最喜欢的 ide 和 go 调试器。带有 go 扩展的 vscode 效果很好 - 只需启动一个调试会话,它就会在 panic 上自动中断。然后您可以检查“调用堆栈”窗口以查看每个 goroutine 的实际位置。

但主要问题是代码过于复杂。您确实只需要一个频道。

这样的东西应该更具可读性,因此更不容易出错:

func FindExits(root []*Node, paths chan []string, path []string) {
    for _, node := range root {
        if node.Value == consts.SUCCESS {
            paths <- path
            return
        }
        FindExits(node.Next, paths, append(path, node.Value))
        if path != nil {
            path = append([]string{}, path...) // detach the slice
        }
    }
}

func FindExitConcurrently(root []*Node, paths chan []string, wg *sync.WaitGroup) {
    FindExits(root, paths, nil)
    wg.Done()
}

func FindPathConcurrently(parentNode *Node) {
    pathCh := make(chan []string)
    var wg sync.WaitGroup
    for _, next := range parentNode.Next {
        wg.Add(1)
        go FindExitConcurrently(next.Next, pathCh, &wg)
    }
    go func() {
        for value := range pathCh {
            fmt.Println(strings.Join(value, ","))
        }
    }()
    wg.Wait()
    close(pathCh)
}

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>