在忽略CTRL-C的同时读取用户的输入

时间:2016-04-13 16:18:08

标签: go

我想在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
                }
            }
        }
    }
}

1 个答案:

答案 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完全退出。