无法处理 goroutine 死锁
Can't handle a go routine deadloock
我正在尝试向频道广播一条消息,我只希望它发送 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() 函数中抛出条件 !ok 以关闭通道并结束等待,但仍然有相同的错误
因为 , the barrier
package you are using is deprecated in favor of Go's included context
package. You should use context
instead. ( The broadcast
您正在使用的软件包目前对您也没有任何好处。)
不过,眼前的问题似乎很明显:(单个)goroutine 运行 workerOne
从通道读取,并且仅当通道 closed(因此 ok
变为 false
)是否调用 bar.Fall()
来删除障碍。同时,(单个)goroutine 运行 匿名发送者函数:
go func() {
for i := 0; i < 5; i++ {
d.x = i
log.Printf("Sending %v", d)
b.Submit(d)
}
<-bar.Barrier()
b.Close()
}()
通过broadcast
package's (very) simple message pub/sub interface, then waits for the barrier to fall. The only goroutine that will drop the barrier—think of it as the only other gopher提交五项可以在这里拯救你的是运行workerOne
。他现在正在频道接收中等待:
v, ok := <-ch
你,在你的主 goroutine 中,正在通过你的 sync.WaitGroup
变量等待:
w.Wait()
gopher 运行 匿名发送函数正在等待:
<-bar.Barrier()
谁——这三个 gophers 中的哪一个 运行 或在各种 Go 例程中等待——将向匿名发件人中的 gopher 发出信号,v, ok := <-ch
应该得到一个 !ok
结果?唯一 可以 的是地鼠 运行 workerOne
,但他卡住了。
broadcast
包永远不会为您关闭频道。注销频道只是将其从广播公司的输出频道中删除,这使未注册的频道保持打开状态;并且完全有效地关闭广播公司只是注销所有频道,再次让它们保持打开状态。所以如果你想关闭你的频道,你必须自己在其他地方做。
或者,您可以修改 workerOne
,使其不依赖于正在关闭的频道。例如,您的变量 d
有一个 x int
和一个 y string
;您可以选择其中一个或两个,并确定一个字符串值 "drop the barrier"——可能还有一些特定的 int
值——表示 "call bar.Fall()
now"。但是,如果这样做,您从这两个非标准包中得到的会更少。
我正在尝试向频道广播一条消息,我只希望它发送 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() 函数中抛出条件 !ok 以关闭通道并结束等待,但仍然有相同的错误
因为 barrier
package you are using is deprecated in favor of Go's included context
package. You should use context
instead. ( The broadcast
您正在使用的软件包目前对您也没有任何好处。)
不过,眼前的问题似乎很明显:(单个)goroutine 运行 workerOne
从通道读取,并且仅当通道 closed(因此 ok
变为 false
)是否调用 bar.Fall()
来删除障碍。同时,(单个)goroutine 运行 匿名发送者函数:
go func() {
for i := 0; i < 5; i++ {
d.x = i
log.Printf("Sending %v", d)
b.Submit(d)
}
<-bar.Barrier()
b.Close()
}()
通过broadcast
package's (very) simple message pub/sub interface, then waits for the barrier to fall. The only goroutine that will drop the barrier—think of it as the only other gopher提交五项可以在这里拯救你的是运行workerOne
。他现在正在频道接收中等待:
v, ok := <-ch
你,在你的主 goroutine 中,正在通过你的 sync.WaitGroup
变量等待:
w.Wait()
gopher 运行 匿名发送函数正在等待:
<-bar.Barrier()
谁——这三个 gophers 中的哪一个 运行 或在各种 Go 例程中等待——将向匿名发件人中的 gopher 发出信号,v, ok := <-ch
应该得到一个 !ok
结果?唯一 可以 的是地鼠 运行 workerOne
,但他卡住了。
broadcast
包永远不会为您关闭频道。注销频道只是将其从广播公司的输出频道中删除,这使未注册的频道保持打开状态;并且完全有效地关闭广播公司只是注销所有频道,再次让它们保持打开状态。所以如果你想关闭你的频道,你必须自己在其他地方做。
或者,您可以修改 workerOne
,使其不依赖于正在关闭的频道。例如,您的变量 d
有一个 x int
和一个 y string
;您可以选择其中一个或两个,并确定一个字符串值 "drop the barrier"——可能还有一些特定的 int
值——表示 "call bar.Fall()
now"。但是,如果这样做,您从这两个非标准包中得到的会更少。