当前位置: 首页 > 面试题库 >

所有goroutine都在睡觉-死锁!\----—错误

穆建华
2023-03-14
问题内容

我想编写三个同时发送整数的并发go例程。现在,我的代码已正确编译,但是在第一次执行后,出现错误“所有goroutine都处于睡眠状态-
死锁!”。我试图找到错误,但是在代码逻辑中找不到任何错误。有人可以帮助我在我的代码中查找错误。我的代码如下。提前致谢。

package main

import "rand"

func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {
    for i := 0; i < 10; i++ {
        y := rand.Intn(10)
        if y%2 == 0 {
            command12 <- y
        }

        if y%2 != 0 {
            command13 <- y
        }
        select {
        case cmd1 := <-response12:
            print(cmd1, " 1st\n")
        case cmd2 := <-response13:
            print(cmd2, " 1st\n")
        }
    }
    close(command12)
}

func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command12:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }

        case x, open := <-response23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response12 <- y
        }

        if y%2 != 0 {
            command23 <- y
        }

    }
}

func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
    for i := 0; i < 10; i++ {
        select {
        case x, open := <-command13:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        case x, open := <-command23:
            {
                if !open {
                    return
                }
                print(x, " 2nd\n")
            }
        }

        y := rand.Intn(10)
        if y%2 == 0 {
            response13 <- y
        }

        if y%2 != 0 {
            response23 <- y
        }

    }
}

func main() {
    command12 := make(chan int)
    response12 := make(chan int)
    command13 := make(chan int)
    response13 := make(chan int)
    command23 := make(chan int)
    response23 := make(chan int)

    go Routine1(command12, response12, command13, response13)
    go Routine2(command12, response12, command23, response23)
    Routine3(command13, response13, command23, response23)
}

谁能告诉我为什么我将Routine2和Routine3声明为go例程,为什么输出为[no output]。我是GO语言的新手,据我从“
http://golang.org/doc/effective_go.html#concurrency
” 了解,go用于在同一地址空间中与其他goroutine并行执行goroutine。所以,问题是所有例程都在运行,但是输出为[no output]。

为了使程序更清晰:我实际上很想做的是在每个例程之间创建两个通道,然后使用一个通道将int发送到另一个通道,并从该例程的另一个通道接收int。例如,例行程序1和3之间的通道是command13和response13。例程1使用command13向例程3发送int,response13从例程3接收int。对于例程3,response13用于向例程1发送int和command13从例程1接收int(命令/响应13代表例程1和例程3之间的通道)。现在,由于三个例程是并发的,并且它们具有特定的例程来处理接收到的味精或发送味精,为什么它们进入死锁状态?


问题答案:
go Routine1(command12, response12,command13, response13 )
go Routine2(command12, response12,command23, response23) // go routine
Routine3(command12, response12,command23, response23 )

这将在新的goroutine中启动Routine1,而主goroutine将继续执行下一条语句。因此,Routine1和Routine2将同时执行,但是Routine2将在Routine2完成后启动。您可能会在这里错过另一个“继续”声明。

然后,我试图遵循您的程序。在Routine1中,您可以

command13 <- y

这将阻止Routine1,直到准备好另一个可以接收您的消息的goroutine。因此,您需要y := <-command13在另一个goroutine中使用。

但是现在,让我们仔细看看其他两个goroutine的参数:

Routine2(command12, response12,command23, response23)
Routine3(command12, response12,command23, response23 )

如您所见,所有goroutine都不具有对command13的访问权限(但是您要两次传递command12)。因此,Routine1或Routine2或Routine3均无法继续。僵局!

我建议您回到绘图板上。首先考虑您要做什么,绘制一些有关预期消息流的图表,然后尝试实现该行为。

从那时起,真的很难调试程序

  • 我不知道你想做什么。没有有关消息流或类似内容的详细描述。实际上,您的代码根本不包含任何文档。
  • 您正在传递通道,这些通道被调用response23到名为的参数response13,依此类推。将它们混合起来很容易。
  • 所有这些通用名称(例如command12等)都使您很难理解该通道应该做什么
  • gofmt在发布之前,对您的源代码来说这是一个好主意:)

首先,我可以向您推荐Go教程中的“ Prime
Numbers”示例。在此示例中,可能的质数从一个goroutine传递到另一个goroutine。此外,此示例还包含一些有关消息流的漂亮图形以及一些非常好的说明。您可能会喜欢。



 类似资料:
  • 问题内容: 对于我的要求之一,我必须创建N个工作程序例程,该例程将由一个监视程序监视。所有工作程序完成后,监视程序必须结束。我的代码以死锁结尾,请帮忙。 问题答案: 您的monitorWorker永不死。当所有工作人员完成时,它将继续等待cs。这将导致死锁,因为其他任何东西都不会继续发送给CS,因此wg永远不会达到0。一种可能的解决方法是,当所有工作程序完成时,让监视器关闭通道。如果for循环在m

  • 问题内容: 我正在尝试剥离一组goroutine,然后等待它们全部完成。 但是,当我运行此代码时,出现以下错误: 我很困惑,因为我写的几乎与文档示例所演示的完全一样。 问题答案: 您需要将指针传递给WaitGroup,而不是WaitGroup对象。当您传递实际的WaitGroup时,Go会生成该值的副本,然后调用该副本。结果是原始的WaitGroup将具有10个Add,而没有Done,并且Wait

  • 问题内容: 给出以下简单的Go程序 我想知道是否有人可以启发我 谢谢 问题答案: 由于您从不关闭通道,因此范围循环将永远不会结束。 您不能在同一频道上发送结果。一种解决方案是使用其他解决方案。 您的程序可以这样修改:

  • 问题内容: 下面的代码与硬编码的JSON数据一起正常工作,但是当我从文件中读取JSON数据时不起作用。我得到使用时的错误。 硬编码JSON数据的工作示例: 输出: 不起作用-读取JSON数据文件的示例: 输出值 主机 问题答案: 当主功能结束时,Go程序结束。 从语言规范 程序执行首先初始化主程序包,然后调用函数main。当该函数调用返回时,程序退出。它不等待其他(非主)goroutine完成。

  • 问题内容: 我不明白为什么这段代码中会发生死锁。我尝试了几种不同的方法来使僵局停止(使用WorkGroup的几种不同版本)。这是我在Go中的第一天,到目前为止,我对相当简单直接的操作的复杂性感到非常失望。我感觉好像缺少了一些明显的东西,但是我发现的所有文档似乎与对我来说是一种非常基本的操作模式都大不相同。所有文档都将原始类型用于通道(int,string),而不是更复杂的类型,所有类型都具有非常基

  • 问题内容: 在进行工作之前,我一直遵循一种检查通道中是否有东西的模式: 这是基于这部视频的。这是我的完整代码: 如果您尝试运行它,则在打印将要中断的消息之前,我们最终将陷入僵局。自上次以来,当chan中没有其他内容时,tbh才有意义,因此我们试图拉出该值,因此出现此错误。但是这样的模式是不可行的。我如何使此代码起作用以及为什么会出现此死锁错误(大概此模式应该起作用?)。 问题答案: 鉴于您在一个频