我想捕获从控制台发送的Ctrl+C (SIGINT)信号,并打印一些部分运行总数。


当前回答

Death是一个简单的库,它使用通道和等待组来等待关闭信号。一旦接收到信号,它就会在所有你想要清除的结构上调用close方法。

其他回答

只是为了记录如果有人需要一种方法来处理Windows上的信号。

我有一个要求,从程序a通过os/exec调用程序B,但程序B从未能够优雅地终止,因为通过cmd.Process.Signal(sycall . sigterm)或其他信号发送信号在Windows上不支持。

我通过创建一个临时文件作为信号来处理这个问题。例如,程序A创建文件.signal。术语和程序B需要检查该文件是否以间隔为基础存在。如果文件存在,它将退出程序,并在需要时处理清理。

我相信还有其他方法,但这招管用。

(在发布的时候)上面接受的答案中有一两个小错字,所以这里是清理后的版本。在这个例子中,当接收到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"

)



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()捕获信号。

如此:

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

在游乐场结帐

看看这个例子

当我们运行这个程序时,它会阻塞等待一个信号。通过输入Ctrl+C(终端显示为^C),我们可以发送一个SIGINT信号,导致程序打印中断,然后退出。

信号。Notify注册给定通道以接收指定信号的通知。

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {

    sig := make(chan os.Signal, 1)
    done := make(chan bool, 1)

    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        sig := <-sig
        fmt.Println()
        fmt.Println(sig)
        done <- true

        fmt.Println("ctrl+c")
    }()

    fmt.Println("awaiting signal")
    <-done
    fmt.Println("exiting")
}

检测HTTP请求取消



package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {

    mux := http.NewServeMux()
    mux.HandleFunc("/path", func(writer http.ResponseWriter, request *http.Request) {

        time.Sleep(time.Second * 5)

        select {
        case <-time.After(time.Millisecond * 10):

            fmt.Println("started")
            return
        case <-request.Context().Done():
            fmt.Println("canceled")
        }
    })

    http.ListenAndServe(":8000", mux)

}