Home > Blockchain >  How can one close a channel in a defer block safely?
How can one close a channel in a defer block safely?

Time:11-19

Consider the following example:

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(2 * time.Second)
    done := make(chan bool)
    defer func() {
        fmt.Println("exiting..")
        done <- true
        close(done)
    }()
    go func(ticker *time.Ticker, done chan bool) {
        for {
            select {
            case <-done:
                fmt.Println("DONE!")
                break
            case <-ticker.C:
                fmt.Println("TICK!...")
            }
        }
    }(ticker, done)
    time.Sleep(7 * time.Second)
}

The goroutine waiting to receive from done never receives as (I am guessing) the main goroutine finished beforehand. However if I change the sleep time of the main goroutine to 8 seconds it receives a message; Why is there this dependency on the sleep time?

Is it because there is that second difference that keeps the goroutine alive and the there isn't enough time to kill it?

How would I than kill the goroutine gracefully?

CodePudding user response:

You need to ensure that main does not return before the goroutine finishes.
The simplest way to do this is using a WaitGroup:

var wg sync.WaitGroup
defer wg.Wait()
wg.Add(1)
go func() {
    defer wg.Done()
    // …

Note that defers run in reverse order, so you must put defer wg.Wait() before defer close(done), otherwise it will deadlock.

  • Related