我想捕获从控制台发送的Ctrl+C (SIGINT)信号,并打印一些部分运行总数。
当前回答
上面所有的代码拼接起来都可以工作,但是gobyexample的信号页面有一个非常干净完整的信号捕获示例。值得在这个列表中加上。
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
done <- true
}()
fmt.Println("awaiting signal")
<-done
fmt.Println("exiting")
}
来源:gobyexample.com/signals
其他回答
你可以使用os/signal包来处理传入信号。Ctrl+C是SIGINT,所以你可以用它来捕获os.Interrupt。
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func(){
for sig := range c {
// sig is a ^C, handle it
}
}()
终止程序并打印信息的方式完全取决于您。
(在发布的时候)上面接受的答案中有一两个小错字,所以这里是清理后的版本。在这个例子中,当接收到Ctrl+C时,我将停止CPU分析器。
// capture ctrl+c and stop CPU profiler
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
log.Printf("captured %v, stopping profiler and exiting..", sig)
pprof.StopCPUProfile()
os.Exit(1)
}
}()
如此:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time" // or "runtime"
)
func cleanup() {
fmt.Println("cleanup")
}
func main() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
cleanup()
os.Exit(1)
}()
for {
fmt.Println("sleeping...")
time.Sleep(10 * time.Second) // or runtime.Gosched() or similar per @misterbee
}
}
在游乐场结帐
只是为了记录如果有人需要一种方法来处理Windows上的信号。
我有一个要求,从程序a通过os/exec调用程序B,但程序B从未能够优雅地终止,因为通过cmd.Process.Signal(sycall . sigterm)或其他信号发送信号在Windows上不支持。
我通过创建一个临时文件作为信号来处理这个问题。例如,程序A创建文件.signal。术语和程序B需要检查该文件是否以间隔为基础存在。如果文件存在,它将退出程序,并在需要时处理清理。
我相信还有其他方法,但这招管用。
这是另一个版本,如果你有一些任务要清理。代码将在它们的方法中留下清理过程。
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
_,done1:=doSomething1()
_,done2:=doSomething2()
//do main thread
println("wait for finish")
<-done1
<-done2
fmt.Print("clean up done, can exit safely")
}
func doSomething1() (error, chan bool) {
//do something
done:=make(chan bool)
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
//cleanup of something1
done<-true
}()
return nil,done
}
func doSomething2() (error, chan bool) {
//do something
done:=make(chan bool)
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
//cleanup of something2
done<-true
}()
return nil,done
}
如果你需要清理主函数,你也需要在主线程中使用go func()捕获信号。