webentwicklung-frage-antwort-db.com.de

Ist es möglich, ein Strg + C-Signal zu erfassen und eine Bereinigungsfunktion "aufgeschoben" auszuführen?

Ich möchte das einfangen Ctrl+C Das Signal (SIGINT) wird von der Konsole gesendet und gibt einige Teillaufsummen aus.

Ist das in Golang möglich?

Hinweis: Als ich die Frage zum ersten Mal gepostet habe, war ich verwirrt Ctrl+C SIGTERM anstelle von SIGINT sein.

178

Sie können das Paket os/signal verwenden, um eingehende Signale zu verarbeiten. ^ C ist SIGINT , damit können Sie os.Interrupt abfangen.

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func(){
    for sig := range c {
        // sig is a ^C, handle it
    }
}()

Die Art und Weise, wie Sie Ihr Programm dazu bringen, Informationen zu beenden und Informationen auszudrucken, liegt ganz bei Ihnen.

220
Lily Ballard

Das funktioniert:

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
    }
}
76
Barry

Um etwas zu den anderen Antworten hinzuzufügen, wenn Sie SIGTERM (das durch den Kill-Befehl gesendete Standardsignal) tatsächlich abrufen möchten, können Sie syscall.SIGTERM anstelle von os.Interrupt verwenden. Beachten Sie, dass die Syscall-Schnittstelle systemspezifisch ist und möglicherweise nicht überall funktioniert (z. B. unter Windows). Aber es funktioniert gut, um beide zu fangen:

c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....
24
adamlamar

Es gab (zum Zeitpunkt der Veröffentlichung) ein oder zwei kleine Tippfehler in der oben akzeptierten Antwort, daher hier die aufgeräumte Version. In diesem Beispiel stoppe ich den CPU-Profiler, wenn Ctrl + C empfangen wird.

// 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)                                                     
  }                                                                
}()    
17
gravitron

Alle oben genannten Funktionen scheinen beim Zusammenfügen zu funktionieren, aber auf der Signalseite von gobyexample gibt es ein wirklich sauberes und vollständiges Beispiel für die Signalerfassung. Es lohnt sich, diese Liste hinzuzufügen.

6
will-ob

Dies ist eine andere Version, die funktioniert, falls Sie einige Aufgaben bereinigen müssen. Code hinterlässt in seiner Methode einen Bereinigungsprozess.

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
}

falls Sie die Hauptfunktion bereinigen müssen, müssen Sie auch das Signal im Haupt-Thread mit go func () erfassen.

0
Hlex