无法处理go例行死线

问题描述 投票:-1回答:1

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

我的代码:

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
        }
    }
}

输出:

2019/12/26 20:34:11 Sending {message : 0}
2019/12/26 20:34:11 Sending {message : 1}
2019/12/26 20:34:11 Sending {message : 2}
2019/12/26 20:34:11 Sending {message : 3}
2019/12/26 20:34:11 Sending {message : 4}
2019/12/26 20:34:11 workerOne() reading : {message : 0}
2019/12/26 20:34:11 workerOne() reading : {message : 1}
2019/12/26 20:34:11 workerOne() reading : {message : 2}
2019/12/26 20:34:11 workerOne() reading : {message : 3}
2019/12/26 20:34:11 workerOne() reading : {message : 4}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x59f530)
        C:/Go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0x59f528)
        C:/Go/src/sync/waitgroup.go:130 +0x6c
main.main()
        C:/Users/DELL/Desktop/work/demos/Design pattern/broadcast/broadcast.go:38 +0x107

goroutine 19 [select]:
github.com/dustin/go-broadcast.(*broadcaster).run(0xc000060420)
        D:/gocode/src/github.com/dustin/go-broadcast/broadcaster.go:39 +0x10f
created by github.com/dustin/go-broadcast.NewBroadcaster
        D:/gocode/src/github.com/dustin/go-broadcast/broadcaster.go:64 +0x103

goroutine 20 [chan receive]:
main.workerOne(0x4f1de0, 0xc000060420)
        C:/Users/DELL/Desktop/work/demos/Design pattern/broadcast/broadcast.go:46 +0xcd
created by main.main
        C:/Users/DELL/Desktop/work/demos/Design pattern/broadcast/broadcast.go:25 +0x8e

goroutine 21 [chan receive]:
main.main.func1(0xc000060440, 0x4f1de0, 0xc000060420)
        C:/Users/DELL/Desktop/work/demos/Design pattern/broadcast/broadcast.go:35 +0x168
created by main.main
        C:/Users/DELL/Desktop/work/demos/Design pattern/broadcast/broadcast.go:29 +0xf7
exit status 2

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

go broadcast goroutine
1个回答
0
投票

作为Adrian noted in a comment,不赞成使用您正在使用的barrier软件包,而推荐使用Go附带的barrier软件包。您应该改用context。 (此刻,您正在使用的context程序包也并没有真正对您有任何帮助。)

但是,眼前的问题似乎非常明显:运行context的(单个)goroutine从通道读取,并且仅当通道为closed(以便context变为broadcast)时,它才会调用broadcast删除障碍。同时,(单个)goroutine运行匿名发送者函数:

workerOne

通过ok程序包的(非常)简单的消息发布/订阅接口提交五项,然后等待障碍消除。唯一会成为障碍的goroutine是正在运行的false,它将它视为唯一可以在此处救助您的其他bar.Fall()。他现在正在等待频道接收:go func() { for i := 0; i < 5; i++ { d.x = i log.Printf("Sending %v", d) b.Submit(d) } <-bar.Barrier() b.Close() }()

您,在您的主要goroutine中,正在通过broadcast变量等待:

broadcast

运行匿名发送者功能的地鼠正在等待:

gopher

[在各种Go例程中正在运行或等待的这三个地鼠中的哪个将向匿名发送者的地鼠发信号,workerOne应该得到    v, ok := <-ch
结果吗?唯一[的人是运行sync.WaitGroup的地鼠,但被卡住了。

w.Wait() 包永远不会为您关闭频道。取消注册频道只会将其从广播公司的输出频道中删除,这会使未注册的频道保持打开状态。而完全关闭广播公司只是取消所有频道的注册,再次使其保持打开状态。因此,如果您想关闭频道,则必须在其他地方自己做。

或者,您可以修改 <-bar.Barrier() ,以使其不依赖于关闭的通道。例如,您的变量v, ok := <-ch有一个!ok和一个workerOne;您可以选择其中的一个或两个,然后确定一个字符串值“降低障碍”(也许也带有某些broadcast值)意味着“立即调用broadcast”。如果这样做,那么从这两个非标准软件包中获得的收益甚至更少。
© www.soinside.com 2019 - 2024. All rights reserved.