Go 语言处理 CTRL+C 中断信号

yufei       5 年, 6 月 前       6741

一个在命令行( 终端 )中运行的 Go 程序,无时不刻需要随时接收 CTRL+C 或者 killkill -9 等信号。

最常见的,就是使用 CTRL+C 组合键来关闭正在运行的程序。这个组合键会产生一个 SIGINT 信号。应用程序可以在收到这个信号时做一些清理工作,然后停止执行并退出。

Go 语言提供了 os/signal 包来处理发送给 Go 语言程序的信息,该包的官方文档为 https://godoc.org/os/signal ,文档很长,有空我们再介绍。今天我们只会使用到它的 signal.Notify 方法。

signal.Notify() 方法

signal.Notify() 方法的原型如下

func Notify(c chan<- os.Signal, sig ...os.Signal)

该方法会捕获所有发给该应用程序的信号,并把感兴趣的信号 sig 参数发送到管道 c 中。如果没有提供 sig 参数,那么该方法会把所有捕获的信号都发送给管道 c

而所有可以捕获的信号都以常量的形式定义在 os 包中,比如常见的 os.Interrupt

使用步骤

signal.Notify 方法的使用步骤有四步,我们以捕获 Ctrl + C 信号为例子

  1. 创建一个 os.Signal 类型的管道,长度为 1 。长度可以根据自己需要自定义

    c := make(chan os.Signal, 1)
    
  2. 捕获 os.Interrupt 信号并把该信号发送到管道 c 中

    signal.Notify(c, os.Interrupt)
    
  3. 阻塞,指导管道 c 中存在一个信号

    s := <-c
    
  4. 捕获信号后做一些其它事情,比如输出

    fmt.Println("Got signal:", s)
    

一般情况下,我们会把 3 和 4 两步骤放在一个 for select 循环中。

范例

Go 语言中处理信号的正确方式,就是使用一个 goroutine 监听来自 signal.Notify() 的信号,并在信号出现时执行一些代码

例如下面的范例,我们在 goroutine 中监听来自 signal.Notify() 的信号 os.Interrupt ,程序会在收到这个信号后做一些清理工作

package main

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

const FILE_NAME = "go-example.txt"

func main() {

    // 设置信号处理
    SetupCloseHandler()

    // 运行我们的程序,也就是创建一个文件并在睡眠 10 秒后继续执行
    CreateFile()
    for {
        fmt.Println("- Sleeping")
        time.Sleep(10 * time.Second)
    }
}

// SetupCloseHandler 在一个新的 goroutine 上创建一个监听器。
// 如果接收到了一个 interrupt 信号,就会立即通知程序,做一些清理工作并退出
func SetupCloseHandler() {
    c := make(chan os.Signal, 2)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    go func() {
        <-c
        fmt.Println("\r- Ctrl+C pressed in Terminal")
        DeleteFiles()
        os.Exit(0)
    }()
}

// 模仿退出时程序的清理工作。
// 因为这只是一个示例,我们并没有对错误进行任何处理
func DeleteFiles() {
    fmt.Println("- Run Clean Up - Delete Our Example File")
    _ = os.Remove(FILE_NAME)
    fmt.Println("- Good bye!")
}

// 创建一个文件,目的是模仿退出时的清理工作
func CreateFile() {
    fmt.Println("- Create Our Example File")
    file, _ := os.Create(FILE_NAME)
    defer file.Close()
}

运行结果如下

$ go run sigint.go 
- Create Our Example File
- Sleeping
- Ctrl+C pressed in Terminal
- Run Clean Up - Delete Our Example File
- Good bye!
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.