我创建了两个例行程序发件人和接收器,发件人将连续从用户(键盘)获取数据并写入流,接收器将独立获取值从流打印到屏幕。两者都是并发使用go例程
在某些时候接收器失败并关闭连接以及退出接收器进入例行程序,但是发送器进入等待用户输入(i / o操作)的例程将不会被关闭。如何在这种情况下退出所有go例程?
以下是此方案的示例代码。
package main
import (
"fmt"
"time"
)
var stop bool = false
func sender() {
str := ""
for !stop {
fmt.Scanf("%s", &str)
fmt.Println("Entered :", str)
}
fmt.Println("Closing sender goroutine")
}
func receiver() {
i := 0
for !stop {
i++
if i > 5 {
stop = true
}
time.Sleep(1 * time.Second)
}
fmt.Println("Closing receiver goroutine")
}
func main() {
go sender()
go receiver()
/* Wait for goroutines to finish */
for !stop {
time.Sleep(1 * time.Millisecond)
}
time.Sleep(1 * time.Second)
panic("Display stack")
}
上面的代码发送器将在5个循环接收器退出接收器进入例程后等待用户输入。 I expect when receiver close, go routine which waiting on i/o has to be closed.
请帮我解决这个问题。
答案 0 :(得分:2)
Dave C& JimB说,使用渠道协调goroutines。这是一个可能有帮助的例子。
从用户收到5条消息后退出:
package main
import "fmt"
var pipe = make(chan string) //shares text entered by user
var stop = make(chan bool) //shares stop signal
func listen() {
for {
var input string
fmt.Scan(&input)
pipe <- input
}
}
func write() {
for i := 0; i < 5; i++ {
var output string
output = <-pipe
fmt.Println("Received", output)
}
stop <- true
}
func main() {
go listen()
go write()
<-stop
}
答案 1 :(得分:1)
首先,您的代码围绕stop
变量进行竞赛。当存在数据竞争时,无法保证您的程序将按照定义运行。使用通道同步goroutine。但这并不是你继续编程的原因。
您的代码在fmt.Scanf
上受阻,并且无法检查stop
条件。由于Stdin上的Read不能被中断(发生在fmt.Scanf
内),因此您需要在再次调用Scanf
之前检查停止条件。如果没有更多的输入,但你有一个待定的Stdin读取,最简单的处理方法就是让goroutine继续运行。有一些相当复杂的方法可以使用被称为“自我管道”的技巧来突破这一点,但它通常不值得努力,因为goroutines很小并且不需要很多资源。
for !stop {
fmt.Scanf("%s", &str)
fmt.Println("Entered :", str)
// use a channel to detect when to exit
select {
case <-stop:
return
default:
}
}