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

问题描述 投票:0回答:1

有人可以解释为什么将答复推送到没有指示缓冲区大小的通道时会出现死锁吗?

当我以这种方式创建确认频道时,我的测试陷入僵局;这个僵局: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)
}
go channel
1个回答
1
投票

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

使用缓冲chan允许goroutine完成发送操作并退出,因此wg.Wait()语句成功,之后主要连续。

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

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

在阻塞主程序之前从chan读取时不会死锁,从而允许goroutine退出。

© www.soinside.com 2019 - 2024. All rights reserved.