golang信号通知 signal.Notify NotifyContext完整示例

在看示例之前有必要先看看Go程序中信号的默认行为,

go中信号的默认行为如下:

SIGHUP、SIGINT或SIGTERM信号会导致程序退出。SIGQUIT、SIGILL、SIGTRAP、SIGABRT、SIGSTKFLT、SIGEMT或SIGSYS信号会导致程序退出并进行堆栈转储。SIGTSTP、SIGTTIN或SIGTTOU信号获取系统默认行为(这些信号由shell用于作业控制)。SIGPROF信号由Go运行时直接处理以实现运行时。CPU配置文件。将捕捉到其他信号,但不会采取任何行动。

如果Go程序启动时忽略了SIGHUP或SIGINT(信号处理程序设置为SIG_IGN),它们将保持被忽略状态。

如果Go程序是用一个非空信号掩码启动的,那么这通常会得到遵守。然而,有些信号是明确取消阻塞的:同步信号SIGILL、SIGTRAP、SIGSTKFLT、SIGCHLD、SIGPROF,以及在Linux上的信号32(SIGCANCEL)和33(SIGSETXID)(SIGCANCEL和SIGSETXID由glibc内部使用)。操作系统启动的子进程。Exec或os/Exec将继承修改后的信号掩码。

信号通知使用示例:

Go 复制代码
package main

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

// 中断信号演示,
// signal.Notify(c, os.Interrupt) 这里的第二个参数即为要中转的信号,如果没有这个参数,所有的信号都会被中转到c
func demoSigInterrupt() {

	c := make(chan os.Signal, 1)   //创建一个用来接收信号的管道 c
	signal.Notify(c, os.Interrupt) //将包中接收到的中断信号(os.Interrupt)转送给管道c; 当程序被ctrl+c中断时中断信号就会被转送给管c
	s := <-c                       // 从管道中读取信息并赋值给s;
	fmt.Println("Got signal:", s)  // Got signal: interrupt
}

// 中转所有信号
func demoSigAll() {
	c := make(chan os.Signal, 1)
	signal.Notify(c) // 不传第二个参数,将所有的OS信号都转送到c
	s := <-c
	fmt.Println("Got signal: ", s)
}

var neverRead = make(chan struct{})

// This example passes a context with a signal to tell a blocking function that
// it should abandon its work after a signal is received.
func demoNotifyContext() {
	// NotifyContext返回一份父上下文的拷贝, 当收到os.Interrupt信号或者stop函数被执行时, 这时这个上下文的通道就会被关闭
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	// 获取当前进程自己
	p, err := os.FindProcess(os.Getpid())
	if err != nil {
		log.Fatal(err)
	}

	// 在unix类的系统中,ctrl+c将发送一个SIGINT信号到执行中的程序
	// 注意下面这个代码仅在unix系统中生效, 可在文件顶部添加 //go:build unix 来指示仅unix系统才会被编译
	// 这里模拟先自己发送一个SIGINT中断信号
	if err := p.Signal(os.Interrupt); err != nil {
		log.Fatal(err)
	}

	// 处理多个管道模拟
	select {
	case <-neverRead:
		fmt.Println("这个不会被执行,因为它是空的,仅作为多管道模拟")
	case <-ctx.Done():
		fmt.Println(ctx.Err()) // prints "context canceled"
		stop()                 // stop receiving signal notifications as soon as possible.
	}

}
func main() {
	// demoSigInterrupt()
	// demoSigAll()
	demoNotifyContext()
	fmt.Println("main ended")
}
相关推荐
Enaium3 分钟前
Rust入门实战 编写Minecraft启动器#3解析资源配置
java·开发语言·rust
我写代码菜如坤4 分钟前
Unity中遇到“Input Button unload_long_back_btn is not setup”问题
开发语言
许思王17 分钟前
【Python】组合数据类型:序列,列表,元组,字典,集合
开发语言·人工智能·python
虫小宝1 小时前
如何在Java中实现PDF生成
java·开发语言·pdf
Java4ye1 小时前
Netty 是如何解析 Redis RESP 协议的——请求篇
后端
菜鸡且互啄692 小时前
在线教育平台,easyexcel使用案例
java·开发语言
电饭叔3 小时前
《python程序语言设计》2018版第5章第52题利用turtle绘制sin函数
开发语言·python
weixin_452600693 小时前
如何为老化的汽车铅酸电池充电
开发语言·单片机·安全·汽车·电机·电源模块·充电桩
Java资深爱好者4 小时前
如何在std::map中查找元素
开发语言·c++
YCCX_XFF214 小时前
ImportError: DLL load failed while importing _imaging: 操作系统无法运行 %1
开发语言·python