【问题标题】:Broadcaster: all goroutines are asleep - deadlockBroadcaster:所有的 goroutine 都在休眠 - 死锁
【发布时间】:2014-05-29 17:06:30
【问题描述】:

下面的代码 (http://play.golang.org/p/ikUtdoKOo5) 应该向多个客户端广播一条消息。但它不起作用,我不知道为什么。

package main

import "fmt"

type Broadcaster struct {
    Clients []Client
}

func (b *Broadcaster) Broadcast(msg string) {
    for _, c := range b.Clients {
        go func() {
            c.Inbox() <- msg
        }()
    }
}

type Client interface {
    Inbox() chan string
}

type TestClient struct {
    Messages chan string
}

func (tc TestClient) Inbox() chan string {
    return tc.Messages
}

func main() {
    client1 := TestClient{Messages: make(chan string)}
    client2 := TestClient{Messages: make(chan string)}
    broadcaster := Broadcaster{Clients: []Client{client1, client2}}

    broadcaster.Broadcast("sos")

    fmt.Printf("client1: '%s'\n", <-client1.Messages)
    fmt.Printf("client2: '%s'\n", <-client2.Messages)
}


错误:

go run main.go
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
        /Users/artem/projects/gocode/src/github.com/artemave/broadcaster/main.go:36 +0x1f3

goroutine 3 [chan send]:
main.func·001()
        /Users/artem/projects/gocode/src/github.com/artemave/broadcaster/main.go:12 +0x5f
created by main.(*Broadcaster).Broadcast
        /Users/artem/projects/gocode/src/github.com/artemave/broadcaster/main.go:13 +0xcd

goroutine 4 [chan send]:
main.func·001()
        /Users/artem/projects/gocode/src/github.com/artemave/broadcaster/main.go:12 +0x5f
created by main.(*Broadcaster).Broadcast
        /Users/artem/projects/gocode/src/github.com/artemave/broadcaster/main.go:13 +0xcd


更新:

go vet 工具揭示了问题:

% go vet
main.go:12: range variable c enclosed by function

【问题讨论】:

    标签: go


    【解决方案1】:

    这是在 for-range 循环中重新分配 c 所带来的一个微妙错误。看起来有点奇怪,但您在 std 库中的几个地方看到了这种模式:

    func (b *Broadcaster) Broadcast(msg string) {
        for _, c := range b.Clients {
            c := c  // redeclare c for the closure
            go func() {
                c.Inbox() <- msg
            }()
        }
    }
    

    http://golang.org/doc/faq#closures_and_goroutines

    【讨论】:

    • 感谢您的链接! go vet 工具会揭示问题。
    【解决方案2】:

    您的问题是变量c 在闭包中的使用。 由于c 是单个变量,所以在执行 go 例程时,c 很可能会设置为 client2,并且两条消息都将被广播到该客户端,而不会向 client1 广播。

    使用函数参数修复它的一种方法:

    func (b *Broadcaster) Broadcast(msg string) {
        for _, c := range b.Clients {       
            go func(c Client) {
                c.Inbox() <- msg                
            }(c)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-22
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      • 2013-11-22
      • 2018-05-28
      • 1970-01-01
      相关资源
      最近更新 更多