【问题标题】:Why the program blocks by the channel in the select?为什么程序会在select中被频道阻塞?
【发布时间】:2022-01-02 15:25:17
【问题描述】:
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
}

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

【问题讨论】:

  • 把“a.exit = make(chan bool)”改成“a.exit = make(chan bool,1)”就好了

标签: go select channel


【解决方案1】:

您的程序阻塞,因为这是您编写的,请考虑以下操作顺序:

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

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

  • 您的 a.f goroutine 在 a.exit &lt;- 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
}

【讨论】:

  • 非常感谢。我知道代码有什么问题,实际上无缓冲通道和大小为 1 的通道之间存在一些差异。在我的程序中,我这样写是因为我想运行很多af(),所以我想如果 af() 停止,它仍然会向 a.exit 通道发送一些信息,以通知其他 af() 到 quit(),所以如果我仍然想使用无缓冲通道,我可能需要添加一个 read主要功能中的频道。感谢您的帮助,我想我明白为什么它是错误的,我可以在我的代码中做什么。
猜你喜欢
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
  • 2020-08-19
相关资源
最近更新 更多