Home > Back-end >  Why does sending to channel is blocked when a panic occurs?
Why does sending to channel is blocked when a panic occurs?

Time:08-26

I am going to show a simple compilable code snipped where I get weird behaviour: after I intentionally cause a panic in processData (because I pass nil-pointer) the sending to channel l.done is blocked!

package main

import (
    "context"
    "fmt"
    "time"
)

type Loop struct {
    done chan struct{}
}

type Result struct {
    ID string
}

func NewLoop() *Loop {
    return &Loop{
        done: make(chan struct{}),
    }
}

func (l *Loop) StartAsync(ctx context.Context) {
    go func() {
        defer func() {
            l.done <- struct{}{} // BLOCKED! But I allocated it in NewLoop ctor
            fmt.Sprintf("done")
        }()
        for {
            /**/
            var data *Result
            l.processData(ctx, data) // passed nil
        }
    }()
}

func (l *Loop) processData(ctx context.Context, data *Result) {
    _ = fmt.Sprintf("%s", data.ID) // intentional panic - OK
}
func main() {
    l := NewLoop()
    l.StartAsync(context.Background())
    time.Sleep(10 * time.Second)
}

I can recover() a panic before sending to channel and I get correct error message. What does happen with channel? It it was closed, I would get panic on sending to closed channel

CodePudding user response:

It's blocking because there isn't anything receiving from the channel. Both the receive & the send operations on an initialized and unbuffered channel will block indefinitely if the opposite operation is missing. I.e. a send to a channel will block until another goroutine receives from that channel, and, likewise, a receive from a channel will block until another goroutine sends to that channel.

So basically

done := new(chan struct{})
done<-struct{}{}

will block forever unless there is another goroutine that receives from the channel, i.e. <-done. That's how channels are supposed to behave. That's how the languages specification defines their behaviour.

  •  Tags:  
  • go
  • Related