キャプチャしたい Ctrl+C (SIGINT
)コンソールから送信されたシグナル。一部の実行合計を出力します。
これはGolangで可能ですか?
注:私が最初に質問を投稿したとき、私は混乱していました Ctrl+C SIGTERM
ではなくSIGINT
である。
これは動作します:
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
}
}
他の回答に少し追加するために、実際にSIGTERM(killコマンドによって送信されるデフォルトのシグナル)をキャッチしたい場合、os.Interruptの代わりにsyscall.SIGTERM
を使用できます。 syscallインターフェースはシステム固有であり、どこでも機能しない可能性があることに注意してください(Windowsなど)。しかし、両方をキャッチするとうまくいきます:
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....
上記の受け入れられた回答には(投稿の時点で)1つまたは2つの小さなタイプミスがあったため、ここにクリーンアップされたバージョンがあります。この例では、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)
}
}()
上記のすべては、接続されたときに機能するように見えますが、 gobyexampleのシグナルページ には、シグナルキャプチャの非常にクリーンで完全な例があります。このリストに追加する価値があります。
これは、クリーンアップするタスクがある場合に機能する別のバージョンです。コードはメソッドにクリーンアッププロセスを残します。
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()を使用してメインスレッドでシグナルをキャプチャする必要があります。