无法处理 goroutine 死锁

我正在尝试向频道广播一条消息,我只希望它发送 5 条消息。但我总是得到这个错误: 致命错误:所有goroutines都睡着了 - 死锁!


我的代码:


package main


import (

    "log"

    "sync"


    broadcast "github.com/dustin/go-broadcast"

    "github.com/pwaller/barrier"

)


//Message boradcasted

type Message struct {

    y string

    x int

}


var w sync.WaitGroup

var bar barrier.Barrier


func main() {


    b := broadcast.NewBroadcaster(100)


    w.Add(1)

    go workerOne(b)


    d := Message{"message :", 0}


    go func() {

        for i := 0; i < 5; i++ {

            d.x = i

            log.Printf("Sending %v", d)

            b.Submit(d)

        }

        <-bar.Barrier()

        b.Close()

    }()

    w.Wait()

}


func workerOne(b broadcast.Broadcaster) {

    ch := make(chan interface{})

    b.Register(ch)


    for {

        v, ok := <-ch

        if ok {

            log.Printf("workerOne() reading : %v", v)

        } else {

            log.Printf("i am here")

            close(ch)

            b.Unregister(ch)

            bar.Fall()

            w.Done()

            return

        }

    }

}

我尝试了一切,但它没有抛出条件!在workerOne()函数中确定以关闭通道并结束等待,但仍然有相同的错误



繁星点点滴滴
浏览 127回答 1
1回答

慕容3067478

正如Adrian 在评论中指出的那样barrier,您正在使用的包已被弃用,取而代之的是 Go 包含的context包。你应该context改用。(目前,broadcast您使用的软件包也对您没有任何好处。)不过,眼前的问题似乎很明显:运行的(单个)goroutineworkerOne从一个通道读取数据,并且只有当通道关闭(因此ok变为false)时,它才会调用bar.Fall()以消除障碍。同时,运行匿名发送者函数的(单个)goroutine:go func() {&nbsp; &nbsp; for i := 0; i < 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; d.x = i&nbsp; &nbsp; &nbsp; &nbsp; log.Printf("Sending %v", d)&nbsp; &nbsp; &nbsp; &nbsp; b.Submit(d)&nbsp; &nbsp; }&nbsp; &nbsp; <-bar.Barrier()&nbsp; &nbsp; b.Close()}()通过包的(非常)简单的消息发布/订阅接口提交五个项目broadcast,然后等待障碍下降。唯一能打破障碍的goroutine——把它想象成唯一可以在这里救你的gopher——是 running workerOne。他现在正在频道接收中等待:&nbsp; &nbsp; v, ok := <-ch你,在你的主 goroutine 中,正在通过你的sync.WaitGroup变量等待:w.Wait()运行匿名发送函数的 gopher 正在等待:&nbsp; &nbsp; <-bar.Barrier()谁——这三个在各种 Go 例程中运行或等待的 gopher 中的哪一个——将向匿名发送者中的 gopher 发出信号,v, ok := <-ch应该得到!ok结果?唯一能做到的就是跑的地鼠workerOne,但他被困住了。该broadcast软件包永远不会为您关闭您的频道。取消注册频道只是将其从广播公司的输出频道中删除,这会使未注册的频道保持打开状态;并且完全有效地关闭广播公司只是取消注册所有频道,再次让它们保持打开状态。因此,如果您希望关闭您的频道,您必须自己在其他地方执行此操作。或者,您可以修改您的workerOne,使其不依赖于正在关闭的通道。例如,你的变量d有一个x int和一个y string; 你可以选择其中一个或两个,并决定一个字符串值“放下障碍”——也许还有一些特定int的值——意味着“bar.Fall()现在调用”。但是,如果您这样做,那么您从这两个非标准软件包中获得的收益会更少。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go