英文:
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
}
我想运行多个 goroutine,并且我希望让主函数通知其他 goroutine 退出。这是我的代码,但程序在 select 中阻塞,程序只输出 "-----over-----",没有输出 "+++++over++++++",代码有什么问题?感谢您的帮助。
英文:
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.
答案1
得分: 0
你的程序阻塞是因为你写的代码导致的,考虑以下操作顺序:
main
协程启动a.f
协程。a.f
协程阻塞,尝试从空通道a.exit
中读取数据。main
将a.exit
设置为无缓冲通道,a.f
协程现在阻塞在读取新通道上,这是允许的。main
向a.exit
写入一个值,a.f
从a.exit
中读取该值,这同步了两个协程,现在都不再阻塞。a.f
协程现在阻塞,尝试向无缓冲的a.exit
通道写入数据,这将永远不会解除阻塞,因为没有其他协程会尝试从该通道中读取数据。main
现在退出,并导致所有其他协程退出,这可能会在第5步之前发生。
所以你的程序从不输出 +++++over++++++
的原因是:
- 你的
a.f
协程在a.exit <- true
处阻塞,因为没有其他协程会从该通道中读取该值。 - 你的
main
协程很可能会在a.f
完成工作之前退出并终止整个程序。
我认为你在询问如何在协程完成后使 main
退出,以下是最简单的示例:
package main
import (
"fmt"
)
type A struct {
exit chan struct{}
}
func (a *A) f() {
defer close(a.exit) // 在 f() 完成后关闭通道,关闭的通道会产生零值,所以 <-a.exit 会解除阻塞
fmt.Println("+++++over++++++")
}
func main() {
a := A{}
go a.f()
a.exit = make(chan struct{})
<-a.exit
}
英文:
Your program blocks because that is what you have written, consider this order of operations:
main
goroutine startsa.f
goroutine.a.f
blocks trying to read from the nil channela.exit
.main
setsa.exit
to be an unbuffered channel,a.f
is now blocked reading from the new channel, this is allowed.main
writes a value intoa.exit
anda.f
reads the value froma.exit
, this synchronises the goroutines, nether are blocked now.a.f
now blocks trying to write into the unbuffereda.exit
, this will never unblock because nobody will ever try to read from the channel again.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 ata.exit <- true
because no other goroutine will read this value from the channel. - Your
main
goroutine will probably exit and terminate the entire program beforea.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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论