duanjuebiao6730 2016-11-04 13:06
浏览 57
已采纳

goroutine睡着了-死锁

In the following code I am trying to spawn MaxOutstanding number of handlers. Each handler loops over items in the queue queue and prints them out, I also write true to the done channel.

In my main function, I start the handlers and write 9 elements to the queue and wait for the 1st element to be written to the done queue.

package main


import "fmt"

type Request struct {
        int32
}
var MaxOutstanding = 5
func handle(queue chan *Request, i int, done chan bool) {
    for r := range queue {
        fmt.Println(i, "---", r)
        done <- true
    }
}

func Serve(clientRequests chan *Request, quit, done chan bool) {
    // Start handlers
    for i := 0; i < MaxOutstanding; i++ {
        go handle(clientRequests, i, done)
    }
    <-quit  // Wait to be told to exit.
}


func main() {
    clientRequests := make(chan *Request)
    quit := make(chan bool)
    done := make(chan bool)

    go Serve(clientRequests, quit, done)

    clientRequests <- &Request{4}
    clientRequests <- &Request{1}
    clientRequests <- &Request{2}
    clientRequests <- &Request{3}

    clientRequests <- &Request{5}
    clientRequests <- &Request{6}
    clientRequests <- &Request{7}
    clientRequests <- &Request{8}
    clientRequests <- &Request{9}
    fmt.Println( "...........>", <- done )
    close(clientRequests)
    close(done)
}

On execution I get the following error. I don't see whats wrong with the implementation, I am even closing the channel.

4 --- &{4}
0 --- &{1}
1 --- &{2}
2 --- &{3}
3 --- &{5}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
        /home/ubuntu/digs-svc/src/digs/go1.go:45 +0x251

goroutine 5 [chan receive]:
main.Serve(0xc82004c060, 0xc82004c0c0, 0xc82004c120)
        /home/ubuntu/digs-svc/src/digs/go1.go:28 +0x92
created by main.main
        /home/ubuntu/digs-svc/src/digs/go1.go:37 +0xb9

goroutine 6 [chan send]:
main.handle(0xc82004c060, 0x0, 0xc82004c120)
        /home/ubuntu/digs-svc/src/digs/go1.go:16 +0x23b
created by main.Serve
        /home/ubuntu/digs-svc/src/digs/go1.go:25 +0x5b

EDIT:

Apparently, the fmt.Println("....", <- done) wasn't enough to signify that there is a consumer to the done channel. I moved the code up in the execution order. A consumer needs to be "listening" on the channel when data is written to it. In my earlier code, the when the first data was written there were no consumer.

Working code.

https://play.golang.org/p/98l2M4XO9t

  • 写回答

2条回答 默认 最新

  • driuwt9557 2016-11-04 13:20
    关注

    You're blocking the iteration over the channel in your handle function with the send on the done channel, because nothing is receiving on the other side.

    Those extra channels aren't really doing anything, and you could just add a WaitGroup to synchronize the handler's exit, then you can remove the done channel which will allow the handler to continue.

    func handle(queue chan *Request, i int, wg *sync.WaitGroup) {
        defer wg.Done()
    
        for r := range queue {
            fmt.Println(i, "---", r)
        }
    }
    
    func Serve(clientRequests chan *Request, wg *sync.WaitGroup) {
        // Start handlers
        for i := 0; i < MaxOutstanding; i++ {
            wg.Add(1)
            go handle(clientRequests, i, wg)
    
        }
    }
    
    func main() {
        clientRequests := make(chan *Request)
        var wg sync.WaitGroup
    
        go Serve(clientRequests, &wg)
    
        for i := int32(0); i < 50; i++ {
            clientRequests <- &Request{i}
        }
    
        close(clientRequests)
        wg.Wait()
    }
    

    https://play.golang.org/p/oUFjZONjhk (note that in the playground, this example seems to currently favor a single goroutine being the receiver. Normally the blocked goroutines will receive randomly, and you can see that behavior if you compile and run normally)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 如何通过代码传输视频到亚马逊平台
  • ¥15 php查询mysql数据库并显示至下拉列表中
  • ¥15 freertos下使用外部中断失效
  • ¥15 输入的char字符转为int类型,不是对应的ascall码,如何才能使之转换为对应ascall码?或者使输入的char字符可以正常与其他字符比较?
  • ¥15 devserver配置完 启动服务 无法访问static上的资源
  • ¥15 解决websocket跟c#客户端通信
  • ¥30 Python调用dll文件输出Nan重置dll状态
  • ¥15 浮动div的高度控制问题。
  • ¥66 换电脑后应用程序报错
  • ¥50 array数据同步问题