有人可以解释为什么将答复推送到没有指示缓冲区大小的通道时会出现死锁吗?
当我以这种方式创建确认频道时,我的测试陷入僵局;这个僵局: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)
}
您将获得死锁,因为如果没有缓冲,请确认没有读取器,所以发送操作将阻塞。同时,您正在等待goroutine在主程序中返回(wg.Wait()
语句)。因此main和goroutine都被阻止了。
使用缓冲chan允许goroutine完成发送操作并退出,因此wg.Wait()
语句成功,之后主要连续。
解决无缓冲通道情况的一种方法是更改您等待goroutine完成的位置,即
reply := <-request.Confirm
fmt.Println(reply.Value)
wg.Wait()
在阻塞主程序之前从chan读取时不会死锁,从而允许goroutine退出。