Go os.Signal、os.Interrupt、os.Kill 信号量的使用

2022年11月20日 3312点热度 1人点赞 0条评论
内容纲要

使用示例:

package main

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

func main() {
    // Set up channel on which to send signal notifications.
    // We must use a buffered channel or risk missing the signal
    // if we're not ready to receive when the signal is sent.
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)

    // Block until a signal is received.
    s := <-c
    fmt.Println("Got signal:", s)
}

Notify 的函数定义如下:

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

os.Signal 表示信号量,信号量有多种,例如 InterruptKill,因此需要使用通道接收,这样可以可以避免信号丢失。

    c := make(chan os.Signal, 1)

然后监听种类型的信号量:

    signal.Notify(c, os.Interrupt, os.Kill)

os.Interrupt 表示中断;
os.Kill 表示杀死;

正常情况下,进程被按下 Ctrl+C,会被终止。但是如果自己订阅了信号量,那么可以一直不停止。

下面示例可以接收两个信号量,然后执行某些操作再退出进程:

package main

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

func main() {
    ci := make(chan os.Signal, 1)
    ck := make(chan os.Signal, 1)
    sleep := make(chan bool, 1)

    signal.Notify(ci, os.Interrupt)
    signal.Notify(ck, os.Kill)
    go interrupt(ci, sleep)
    go kill(ck, sleep)

    <-sleep
}
func interrupt(ci chan os.Signal, sleep chan bool) {
    s := <-ci
    fmt.Println("进程被中断:", s)
    sleep <- true
}

func kill(ck chan os.Signal, sleep chan bool) {
    s := <-ck
    fmt.Println("进程被杀死", s)
    sleep <- true
}

按下 Ctrl+C

file

当然,如果是 Kill,那么进程可能会被直接杀死,而不会出现提示。

任务管理器杀死进程:

file
file

如果是 Linux 中,则还能有点效果。

file

停止监听信号量:

signal.Stop(ci)

Go 中支持的信号量:

信号值 动作 说明
SIGHUP 1 Term 终端控制进程结束(终端连接断开)
SIGINT 2 Term 用户发送INTR字符(Ctrl+C)触发
SIGQUIT 3 Core 用户发送QUIT字符(Ctrl+/)触发
SIGILL 4 Core 非法指令(程序错误、试图执行数据段、栈溢出等)
SIGABRT 6 Core 调用abort函数触发
SIGFPE 8 Core 算术运行错误(浮点运算错误、除数为零等)
SIGKILL 9 Term 无条件结束程序(不能被捕获、阻塞或忽略)
SIGSEGV 11 Core 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作)
SIGPIPE 13 Term 消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作)
SIGALRM 14 Term 时钟定时信号
SIGTERM 15 Term 结束程序(可以被捕获、阻塞或忽略)
SIGUSR1 30,10,16 Term 用户保留
SIGUSR2 31,12,17 Term 用户保留
SIGCHLD 20,17,18 Ign 子进程结束(由父进程接收)
SIGCONT 19,18,25 Cont 继续执行已经停止的进程(不能被阻塞)
SIGSTOP 17,19,23 Stop 停止进程(不能被捕获、阻塞或忽略)
SIGTSTP 18,20,24 Stop 停止进程(可以被捕获、阻塞或忽略)
SIGTTIN 21,21,26 Stop 后台程序从终端中读取数据时触发
SIGTTOU 22,22,27 Stop 后台程序向终端中写数据时触发

其他示例:

package main

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

func main() {
    SigChan := make(chan os.Signal, 1)

    signal.Notify(SigChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

    sig := <-SigChan

    switch sig {
    case syscall.SIGHUP:
        fmt.Println("\nSIGHUP signal generated")

    case syscall.SIGINT:
        fmt.Println("\nSIGINT signal generated")

    case syscall.SIGTERM:
        fmt.Println("\nSIGTERM signal generated")

    case syscall.SIGQUIT:
        fmt.Println("\nSIGQUIT signal generated")

    default:
        fmt.Println("\nUNKNOWN signal generated")
    }
}

痴者工良

高级程序员劝退师

文章评论