golang signal信号处理
2022-04-03 17:02 youxin 阅读(696) 评论(0) 编辑 收藏 举报1、使用场景
实际项目中,我们希望修改了配置文件后,但又不想通过重启进程让它重新加载配置文件,可以使用signal的方式进行信号传递,或者我们希望通过信号控制,实现一种优雅的退出方式。Golang为我们提供了signal包,实现信号处理机制,允许Go 程序与传入的信号进行交互。
2、常用的Term信号
3、简单的栗子
package main import ( "fmt" "os" "os/signal" ) func main() { c := make(chan os.Signal) signal.Notify(c) fmt.Println("start..") s := <-c fmt.Println("End...", s) }
1)传递SIGINT信号
[homework@xxxxx signal]$ go run monitor.go
start..
#此时,CTL+C发送一个SIGINT信号量,得到输出为:
[homework@xxxxx signal]$ go run monitor.go
start..
^CEnd... interrupt
(2)传递SIGTERM信号
打开2个Term窗口
第一个运行go run monitor.go程序
第二个执行:ps -ef | grep monitor.go | grep grep -v | awk '{print $2}' | xargs kill
#此时,kill命令发送一个SIGTERM信号量,得到输出为:
[homework@xxxxx signal]$ go run monitor.go
start..
Terminated
4、优雅的退出守护进程
(1)何为优雅(graceful)?
Linux Server端的应用程序经常会长时间运行,在运行过程中,可能申请了很多系统资源,也可能保存了很多状态。
在这些场景下,我们希望进程在退出前,可以释放资源或将当前状态dump到磁盘上或打印一些重要的日志,即希望进程优雅退出。
(2)从对优雅退出的理解不难看出:优雅退出可以通过捕获SIGTERM来实现。
A、注册SIGTERM信号的处理函数并在处理函数中做一些进程退出的准备,信号处理函数的注册sigaction()来实现。
B、在主进程的main()中,通过类似于while(!fQuit)的逻辑来检测那个flag变量,一旦fQuit在signal handler function中被置为true,则主进程退出while()循环,接下来就是一些释放资源或dump进程当前状态或记录日志的动作,完成这些后,主进程退出。
栗子:优雅退出go守护进程
package main import ( "fmt" "os" "os/signal" "syscall" "time" ) func main() { //创建监听退出chan c := make(chan os.Signal) //监听指定信号 ctrl+c kill signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2) go func() { for s := range c { switch s { case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT: fmt.Println("Program Exit...", s) GracefullExit() case syscall.SIGUSR1: fmt.Println("usr1 signal", s) case syscall.SIGUSR2: fmt.Println("usr2 signal", s) default: fmt.Println("other signal", s) } } }() fmt.Println("Program Start...") sum := 0 for { sum++ fmt.Println("sum:", sum) time.Sleep(time.Second) } } func GracefullExit() { fmt.Println("Start Exit...") fmt.Println("Execute Clean...") fmt.Println("End Exit...") os.Exit(0) }
5、信号的订阅
信号的订阅是通过 channel实现的,每个os.Signal channel 都会收听自己相应的事件集。
。golang中对信号的处理主要使用os/signal包中的两个方法:一个是notify方法用来监听收到的信号;一个是 stop方法用来取消监听。
监听信号
notify方法原型
func Notify(c chan<- os.Signal, sig ...os.Signal)
第一个参数表示接收信号的管道
第二个及后面的参数表示设置要监听的信号,如果不设置表示监听所有的信号。
Sometimes we'd like our Go programs to intelligently handle Unix signals. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool stop processing input if it receives a SIGINT. Here's how to handle signals in Go with channels
package main import ( "fmt" "os" "os/signal" "syscall" ) func main() { sigs := make(chan os.Signal, 1) done := make(chan bool, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) go func() { sig := <-sigs fmt.Println("") fmt.Println(sig) done <- true }() fmt.Println("awaiting signal") <-done fmt.Println("exiting") }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2015-04-03 Linux命令 lsof使用 文件删除但是空间未被释放
2015-04-03 gdb多线程调试
2015-04-03 gdb core
2014-04-03 YII 主题
2013-04-03 flickr api 入门教程
2012-04-03 c++设置左对齐
2012-04-03 Error C2361: initialization of (identifier) is skipped by (default) label