我想在go中读取用户输入并忽略用户试图通过捕获CTRL-C.
来尝试杀死我的进程。我将goroutine旋转到陷阱CTRL-C
并写入通道。在这个阶段,我希望控制能够在主goroutine中返回case <-intr
,但这种情况并没有发生。
这是运行的输出:
$ go run read.go
Enter text: hello
Entered:hello
$go run read.go
Enter text: ^CGot signal interrupt
Exiting signal handler..
Invalid input2
Interrupted.. Continuing
Enter text: ^C
Invalid input2
Enter text: ^C
Invalid input2
Enter text: ^C^C^C^C
Invalid input2
Enter text: ^C
Invalid input2
Enter text: ^C
Invalid input2
Enter text:
第一个CTRL-C被困住了,退出后不久,似乎主要的goroutine正在执行r := bufio.NewReader(os.Stdin)
当我稍后按CTRL-C作为输入时,它只被视为文本,并且不会调用信号处理程序。
我的代码如下(goplay link:http://play.golang.org/p/LiKZMYGr00)
package main
import ("fmt"
"bufio"
"os"
"os/signal"
"syscall"
"io"
"strings"
)
func main() {
c := make(chan os.Signal)
intr := make(chan bool)
signal.Notify(c, syscall.SIGINT)
go func() {
s := <-c
fmt.Println("Got signal", s)
fmt.Println("Exiting signal handler..")
intr <- true
return
}()
breakOutOfHere:
for {
select {
case <-intr:
fmt.Println("Interrupted.. Continuing")
continue
default:
fmt.Printf("Enter text: ")
r := bufio.NewReader(os.Stdin)
text, ret := r.ReadString('\n')
if ret == io.EOF {
fmt.Println("Invalid input1")
continue
} else if ret == nil {
text = strings.TrimSpace(text)
if text == "" {
fmt.Println("Invalid input2")
continue
} else {
fmt.Printf("Entered:%s\n", text)
break breakOutOfHere
}
}
}
}
}
答案 0 :(得分:4)
signal.Notify
都会向指定的通道发送信号信息。但在你的代码中,在第一个信号之后,例程就完成了。因此,它无法再次捕获信号。
一种简单的方法是,你需要在go例程中使用select子句进行无限循环。
go func(c chan os.Signal, quit chan bool) {
for {
select {
case <-c:
fmt.Println("Got interrupt signal")
fmt.Println("Exiting signal handler..")
intr <- true
case <-quit:
fmt.Println("quit")
return
}
}
}(c, quit)
此处使用频道quit
来请求go-routine完全退出。