为什么程序会被select中的频道阻塞?

Why the program blocks by the channel in the select?

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
}

我想要 运行 多个 goroutines,我想让 main func 通知其他 goroutine 退出。 这是我的代码,但是select中的程序块,程序只输出“-----over-----”,没有“+++++over++++++”,代码有什么问题?感谢您的帮助。

你的程序阻塞是因为那是你写的,考虑这个操作顺序:

  1. main goroutine 启动 a.f goroutine.
  2. a.f 阻止尝试从 nil 通道读取 a.exit
  3. maina.exit 设置为无缓冲通道,a.f 现在被阻止从新通道读取,这是允许的。
  4. main 将一个值写入 a.exit 并且 a.fa.exit 读取值,这同步了 goroutines,下层现在被阻塞了。
  5. a.f 现在阻止尝试写入未缓冲的 a.exit,这将永远不会取消阻止,因为没有人会再次尝试从通道读取。
  6. main 现在退出并导致所有其他 goroutines 退出,这可能发生在第 5 步之前。

所以你的程序从不输出 +++++over++++++ 的原因是:

  • 你的 a.f goroutine 在 a.exit <- true 阻塞,因为没有其他 goroutine 会从通道读取这个值。
  • 您的 main goroutine 可能会在 a.f 完成工作之前退出并终止整个程序。

我想你问的是如何在 goroutine 完成后让 main 退出,这是最简单的例子:

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
}