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

所有goroutine都在睡觉-死锁

谯翔
2023-03-14
问题内容

对于我的要求之一,我必须创建N个工作程序例程,该例程将由一个监视程序监视。所有工作程序完成后,监视程序必须结束。我的代码以死锁结尾,请帮忙。

import "fmt"
import "sync"
import "strconv"

func worker(wg *sync.WaitGroup, cs chan string, i int ){
    defer wg.Done()
    cs<-"worker"+strconv.Itoa(i)    
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    defer wg.Done()
    for i:= range cs {
            fmt.Println(i)
     }
}
func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i:=0;i<10;i++{
             wg.Add(1)
             go worker(wg,cs,i)
    }

    wg.Add(1)
    go monitorWorker(wg,cs)
    wg.Wait()
}

问题答案:

您的monitorWorker永不死。当所有工作人员完成时,它将继续等待cs。这将导致死锁,因为其他任何东西都不会继续发送给CS,因此wg永远不会达到0。一种可能的解决方法是,当所有工作程序完成时,让监视器关闭通道。如果for循环在main中,它将结束循环,从main返回,并结束程序。

例如:http :
//play.golang.org/p/nai7XtTMfr

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    for i := range cs {
        fmt.Println(i)

    }
}

编辑: 这是对OP的第一条评论的答案。

您的程序包含三个需要同步的部分。首先,您所有的员工都需要发送数据。然后,您的打印循环需要打印该数据。然后,您的主要功能需要返回,从而结束程序。在您的示例中,所有工作程序都发送数据,所有数据都被打印,但是消息从未发送给main,它应该正常返回。

在我的示例中,main进行打印,而“ monitorWorker”仅告诉main何时接收到需要打​​印的每条数据。这样,程序可以正常结束,而不会死锁。

如果您坚持将打印循环放在另一个goroutine中,则可以这样做。但是随后需要将额外的通信发送到main,以便它返回。在下一个示例中,我将使用一个通道来确保在打印所有数据时的主要目的。

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func printWorker(cs <-chan string, done chan<- bool) {
    for i := range cs {
        fmt.Println(i)
    }

    done <- true
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    done := make(chan bool, 1)
    go printWorker(cs, done)
    <-done
}


 类似资料:
  • 问题内容: 我想编写三个同时发送整数的并发go例程。现在,我的代码已正确编译,但是在第一次执行后,出现错误“所有goroutine都处于睡眠状态- 死锁!”。我试图找到错误,但是在代码逻辑中找不到任何错误。有人可以帮助我在我的代码中查找错误。我的代码如下。提前致谢。 谁能告诉我为什么我将Routine2和Routine3声明为go例程,为什么输出为[no output]。我是GO语言的新手,据我从

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

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

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

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

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