进入例程通道和WaitGroup致命错误:所有goroutine都处于睡眠状态-死锁

时间:2019-11-03 14:47:41

标签: go channel

有人可以解释为什么在对没有指示缓冲区大小的通道进行回复时出现死锁吗?

以这种方式创建确认频道时,我的测试陷入僵局;
这个僵局:deadlock

   request := RequestMessage{
        Value:   "make it rain",
        Confirm: make(chan *ReplyMessage),
    }

但不是这样创建的;
这个不会死锁:no deadlock

    request := RequestMessage{
        Value:   "make it rain",
        Confirm: make(chan *ReplyMessage,1),
    }
package main

import (
    "fmt"
    "sync"
)

type ReplyMessage struct {
    Value string
}

type RequestMessage struct {
    Value   string
    Confirm chan *ReplyMessage
}

var requestChannel chan *RequestMessage

func main() {
    requestChannel = make(chan *RequestMessage, 10) // 8 is channel buffer size
    request := RequestMessage{
        Value:   "make it rain",
        Confirm: make(chan *ReplyMessage),
    }
    requestChannel <- &request

    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done() // invoke Done on the WaitGroup when finished
        request := <-requestChannel
        fmt.Printf("Got Request: %s\n", request.Value)
        reply := ReplyMessage{Value: "hi"}
        request.Confirm <- &reply

    }()

    wg.Wait()

    reply := <-request.Confirm
    fmt.Println(reply.Value)
}

1 个答案:

答案 0 :(得分:1)

您会陷入僵局,因为如果没有缓冲,请确认没有读取器,所以发送操作将阻塞。同时,您正在等待goroutine在主程序中返回(wg.Wait()语句)。因此main和goroutine都被阻止了。

使用缓冲的chan可以使goroutine完成发送操作并退出,因此wg.Wait()语句成功,之后继续执行主要操作。

一种解决无缓冲chan情况的方法是更改​​您等待goroutine完成的位置,即

reply := <-request.Confirm
fmt.Println(reply.Value)
wg.Wait()

在阻塞主机之前,您不会从chan中读取死锁,因此可以使goroutine退出。