Home > Back-end >  Why the program blocks by the channel in the select?
Why the program blocks by the channel in the select?

Time:11-25

package main

import (
    "fmt"
)

type A struct{
    exit chan bool
}

func (a *A) f(){
    select{
        //the routine process

        //quit
        case <- a.exit:

                fmt.Println("-----over-----")
                a.exit <- true
                fmt.Println("     over      ")              
        }
}

func main() {

    a := A{}
    
    go a.f()
    a.exit = make(chan bool)
    
    a.exit <- true
}

I'd like to run muti goroutines,and I want let the main func to notice other goroutine to quit. here is my code,but the program block in the select,the program only output "-----over-----",without " over ",what's wrong with the code?Grateful for your help.

CodePudding user response:

Your program blocks because that is what you have written, consider this order of operations:

  1. main goroutine starts a.f goroutine.
  2. a.f blocks trying to read from the nil channel a.exit.
  3. main sets a.exit to be an unbuffered channel, a.f is now blocked reading from the new channel, this is allowed.
  4. main writes a value into a.exit and a.f reads the value from a.exit, this synchronises the goroutines, nether are blocked now.
  5. a.f now blocks trying to write into the unbuffered a.exit, this will never unblock because nobody will ever try to read from the channel again.
  6. main now exits and causes all other goroutines to exit, this might happen before step 5.

So the reasons your program never outputs over are:

  • Your a.f goroutine blocks at a.exit <- true because no other goroutine will read this value from the channel.
  • Your main goroutine will probably exit and terminate the entire program before a.f can finish working.

I think you are asking how to make main exit after the goroutine is finished, this is the most simple example of that:

package main

import (
    "fmt"
)

type A struct {
    exit chan struct{}
}

func (a *A) f() {
    defer close(a.exit) // Close the chanel after f() finishes, closed channels yield the zero-value so <-a.exit will unblock

    fmt.Println("     over      ")
}

func main() {
    a := A{}
    go a.f()
    a.exit = make(chan struct{})

    <-a.exit
}
  • Related