在Golang中防止Ctrl+C打断exec.Command
Prevent Ctrl+C from interrupting exec.Command in Golang
我注意到即使中断调用已通过 signal.Notify
拦截,以 exec.Command
启动的进程也会被中断。我做了以下示例来说明问题:
package main
import (
"log"
"os"
"os/exec"
"os/signal"
"syscall"
)
func sleep() {
log.Println("Sleep start")
cmd := exec.Command("sleep", "60")
cmd.Run()
log.Println("Sleep stop")
}
func main() {
var doneChannel = make(chan bool)
go sleep()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
go func() {
<-c
log.Println("Receved Ctrl + C")
}()
<-doneChannel
}
如果在此程序 运行 时按下 Ctrl+C,它将打印:
2015/10/16 10:05:50 Sleep start
^C2015/10/16 10:05:52 Receved Ctrl + C
2015/10/16 10:05:52 Sleep stop
显示 sleep
命令被中断。虽然 Ctrl+C 被成功捕获,但主程序并没有退出,只是 sleep
命令受到影响。
知道如何防止这种情况发生吗?
shell 将在您按下 ctrl+c
时向整个进程组发出信号。如果直接向父进程发送信号,子进程将不会收到信号。
为了防止 shell 向子进程发出信号,您需要使用 syscall.SysProcAttr
中的 Setpgid
和 Pgid
字段在其自己的进程组中启动命令在开始流程之前
cmd := exec.Command("sleep", "60")
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
你可以忽略syscall.SIGINT
信号,这样就不会传递给exec.Command
。
func main() {
var doneChannel = make(chan bool)
signal.Ignore(syscall.SIGINT)
go func() {
log.Println("Sleep start")
cmd := exec.Command("sleep", "10")
cmd.Run()
log.Println("Sleep stop")
doneChannel <- true
}()
<-doneChannel
}
我注意到即使中断调用已通过 signal.Notify
拦截,以 exec.Command
启动的进程也会被中断。我做了以下示例来说明问题:
package main
import (
"log"
"os"
"os/exec"
"os/signal"
"syscall"
)
func sleep() {
log.Println("Sleep start")
cmd := exec.Command("sleep", "60")
cmd.Run()
log.Println("Sleep stop")
}
func main() {
var doneChannel = make(chan bool)
go sleep()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
go func() {
<-c
log.Println("Receved Ctrl + C")
}()
<-doneChannel
}
如果在此程序 运行 时按下 Ctrl+C,它将打印:
2015/10/16 10:05:50 Sleep start
^C2015/10/16 10:05:52 Receved Ctrl + C
2015/10/16 10:05:52 Sleep stop
显示 sleep
命令被中断。虽然 Ctrl+C 被成功捕获,但主程序并没有退出,只是 sleep
命令受到影响。
知道如何防止这种情况发生吗?
shell 将在您按下 ctrl+c
时向整个进程组发出信号。如果直接向父进程发送信号,子进程将不会收到信号。
为了防止 shell 向子进程发出信号,您需要使用 syscall.SysProcAttr
中的 Setpgid
和 Pgid
字段在其自己的进程组中启动命令在开始流程之前
cmd := exec.Command("sleep", "60")
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
你可以忽略syscall.SIGINT
信号,这样就不会传递给exec.Command
。
func main() {
var doneChannel = make(chan bool)
signal.Ignore(syscall.SIGINT)
go func() {
log.Println("Sleep start")
cmd := exec.Command("sleep", "10")
cmd.Run()
log.Println("Sleep stop")
doneChannel <- true
}()
<-doneChannel
}