Je veux capturer le Ctrl+C (SIGINT
) signal envoyé depuis la console et affiche certains totaux partiels.
Est-ce possible à Golang?
Remarque: lorsque j'ai posté la question pour la première fois, j'étais confus au sujet de Ctrl+C étant SIGTERM
au lieu de SIGINT
.
Vous pouvez utiliser le paquet os/signal pour gérer les signaux entrants. ^ C est SIGINT , vous pouvez donc utiliser ceci pour intercepter 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
}
}()
La manière dont vous faites en sorte que votre programme se termine et imprime des informations vous appartient entièrement.
Cela marche:
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
}
}
Pour ajouter un peu aux autres réponses, si vous voulez réellement attraper SIGTERM (le signal par défaut envoyé par la commande kill), vous pouvez utiliser syscall.SIGTERM
à la place de os.Interrupt. Notez que l’interface syscall est spécifique au système et risque de ne pas fonctionner partout (par exemple sous Windows). Mais cela fonctionne bien pour attraper les deux:
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....
Il y avait (au moment de la publication) une ou deux petites fautes de frappe dans la réponse acceptée ci-dessus, alors voici la version corrigée. Dans cet exemple, j'arrête le profileur de la CPU lors de la réception de Ctrl + C.
// 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)
}
}()
Tout ce qui précède semble fonctionner une fois raccordé, mais la page des signaux de gobyexample présente un exemple très net et complet de capture de signal. Cela vaut la peine d’être ajouté à cette liste.
C'est une autre version qui fonctionne dans le cas où vous auriez des tâches à nettoyer. Code laissera le processus de nettoyage dans leur méthode.
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
}
si vous avez besoin de nettoyer la fonction principale, vous devez également capturer le signal dans le thread principal en utilisant go func ().