Changing channel from unbuffered to buffered prevents goroutine from running

95 views
Skip to first unread message

Dean Schulze

unread,
Feb 11, 2022, 12:50:42 AM2/11/22
to golang-nuts
Here is an exercise using channels and select in a goroutine.  If the disconnect channel is changed to a buffered channel the goroutine doesn't run at all.

Why does changing from an unbuffered to a buffered channel prevent running the goroutine?

    func SelectDemo(wg *sync.WaitGroup) {
   
            messageCh := make(chan int, 10)
            disconnectCh := make(chan struct{})
            //        go routine won't run if channel is buffered
            //disconnectCh := make(chan struct{}, 1)
   
            defer close(messageCh)
            defer close(disconnectCh)
            go func() {
                    fmt.Println("  goroutine")
                    wg.Add(1)
                    for {
                            select {
                            case v := <-messageCh:
                                    fmt.Println(v)
                            case <-disconnectCh:
                                    fmt.Println("  disconnectCh")
                    //  empty the message channel before exiting
                                    for {
                                            select {
                                            case v := <-messageCh:
                                                    fmt.Println(v)
                                            default:
                                                    fmt.Println("  disconnection, return")
                                                    wg.Done()
                                                    return
                                            }
                                    }
                            }
                    }
            }()
   
            fmt.Println("Sending ints")
            for i := 0; i < 10; i++ {
                    messageCh <- i
            }
   
            fmt.Println("Sending done")
            disconnectCh <- struct{}{}
    }

Here's the code to call the function from main.  I use the wait group to assure that the goroutine completes before the program exits:

        wg := sync.WaitGroup{}
        ch09.SelectDemo(&wg)
        wg.Wait()

Ian Lance Taylor

unread,
Feb 11, 2022, 2:47:09 AM2/11/22
to Dean Schulze, golang-nuts
On Thu, Feb 10, 2022, 9:52 PM Dean Schulze <dean.w....@gmail.com> wrote:
Here is an exercise using channels and select in a goroutine.  If the disconnect channel is changed to a buffered channel the goroutine doesn't run at all.

Why does changing from an unbuffered to a buffered channel prevent running the goroutine?

    func SelectDemo(wg *sync.WaitGroup) {
   
            messageCh := make(chan int, 10)
            disconnectCh := make(chan struct{})
            //        go routine won't run if channel is buffered
            //disconnectCh := make(chan struct{}, 1)
   
            defer close(messageCh)
            defer close(disconnectCh)
            go func() {
                    fmt.Println("  goroutine")
                    wg.Add(1)

In order for a WaitGroup to work, you need to call wg.Add before the go statement, not in the goroutine that it starts.

Ian




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/533e6da1-e529-4cd3-a18d-1a4ccf09b947n%40googlegroups.com.

Dean Schulze

unread,
Feb 11, 2022, 10:06:55 AM2/11/22
to golang-nuts
The WaitGroup works if wg.Add() is called within the goroutine.  The only purpose for the WaitGroup is to keep main from exiting before the goroutine has completed.

Moving wg.Add() outside of the goroutine has no effect if the channel is unbuffered.  But if I make the channel buffered and move the wg.Add() outside the goroutine then the code runs in a loop printing 0 and never stops.  This is another behavior that I don't understand.

Why does making disconnectCh buffered cause the goroutine to never run, or to run in a loop printing 0?

Dean Schulze

unread,
Feb 11, 2022, 10:36:02 AM2/11/22
to golang-nuts
Correction to my first response:  Putting the wg.Add() inside the goroutine works as long as the goroutine runs.  But the program could exit before the goroutine starts.  To avoid this the wg.Add() should be outside the goroutine, as you said.

The big problem with this code is that the defer close() calls should be in the goroutine otherwise the channels could be closed when the function exits while the goroutine is still running.

On Friday, February 11, 2022 at 12:47:09 AM UTC-7 Ian Lance Taylor wrote:

Dean Schulze

unread,
Feb 11, 2022, 11:51:03 AM2/11/22
to golang-nuts
The loop printing 0s was caused by having the defer close() statements outside the goroutine.  The channels were being closed before the goroutine ran and the gorouting was continuously reading from a closed channel.  Hence the 0s.

The defer close() statements have to be inside the goroutine.

Reply all
Reply to author
Forward
0 new messages