Golang中的信号处理

Golang中的信号处理

一,信号类型

Linux 使用34-64信号用作实时系统中。命令 man 7 signal 提供了官方的信号介绍。

在POSIX.1-1990标准中定义的信号列表

信号 动作 说明
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 后台程序向终端中写数据时触发

在SUSv2和POSIX.1-2001标准中的信号列表:

信号 动作 说明
SIGTRAP 5 Core Trap指令触发(如断点,在调试器中使用)
SIGBUS 0,7,10 Core 非法地址(内存地址对齐错误)
SIGPOLL Term Pollable event (Sys V). Synonym for SIGIO
SIGPROF 27,27,29 Term 性能时钟信号(包含系统调用时间和进程占用CPU的时间)
SIGSYS 12,31,12 Core 无效的系统调用(SVr4)
SIGURG 16,23,21 Ign 有紧急数据到达Socket(4.2BSD)
SIGVTALRM 26,26,28 Term 虚拟时钟信号(进程占用CPU的时间)(4.2BSD)
SIGXCPU 24,24,30 Core 超过CPU时间资源限制(4.2BSD)
SIGXFSZ 25,25,31 Core 超过文件大小资源限制(4.2BSD)

二,golang通过协程处理指定的信号

package main

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

func main() {
	// start goroutine to listen some signal
	go signalListen()
	// main loop
	for {
		time.Sleep(30 * time.Second)
		fmt.Println("main loop.")
	}
}

func signalListen() {
	// init os.signal channel
	c := make(chan os.Signal)
	// define catch signal
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	for {
		// wait channel
		sig := <-c
		// when receive signal,then notify channel,and print the follow info.
		fmt.Println("receive signal:", sig)
	}
}

三,如何通过信号退出后台demo

package main

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

//创建监听退出chan
var c = make(chan os.Signal)

func main()  {

	//监听指定信号 ctrl+c kill
	signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
	go signalProcess()

	fmt.Println("start...")
	num := 0
	for {
		num++
		fmt.Println("seconds : ", num)
		time.Sleep(time.Second)
	}
}

func signalProcess() {
	for s := range c {
		switch s {
		case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
			fmt.Println("exit signal: ", s)
			ExitFunc()
		case syscall.SIGUSR1:
			fmt.Println("usr1", s)
		case syscall.SIGUSR2:
			fmt.Println("usr2", s)
		default:
			fmt.Println("other", s)
		}
	}
	return
}

func ExitFunc()  {
	fmt.Println("begin exit!!!")
	fmt.Println("clean!!!")
	fmt.Println("end exit!!!")
	os.Exit(0)
}

上面的例子可以应用于,demo通过startProcess启动了很多子进程,当前程序如果退出,不管理这些子进程,那么他们将成为孤儿进程被init进程接管,如果这些进程,占用了公共资源,比如端口,那么下次启动demo,端口将被占用,无法正常使用。那么我们就可以通过此方法来监听信号,尽可能的避免这种情况产生。

尽管如此,还有一些情况是我们无法处理的,比如:SIGKILL,SIGSTOP这两个信号,是无法被捕捉到的,也就是说,如果通过这两个信号结束程序,我们还是无法处理善后工作。





你可能感兴趣的:(技术,golang)