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")
}
相关推荐
偷光14 小时前
浏览器中的隐藏IDE: Elements (元素) 面板
开发语言·前端·ide·php
Paul_092014 小时前
golang面经——内存相关模块
服务器·网络·golang
DKPT14 小时前
JVM栈溢出和堆溢出哪个先满?
java·开发语言·jvm·笔记·学习
海梨花14 小时前
今日八股——JVM篇
jvm·后端·面试
gopyer18 小时前
180课时吃透Go语言游戏后端开发6:Go语言的循环语句
开发语言·游戏·golang·循环语句
Pr Young19 小时前
服务优雅停止和服务优雅启动
后端
嘟嘟MD20 小时前
程序员副业 | 2025年9月复盘
后端·aigc
楼田莉子21 小时前
Qt开发学习——QtCreator深度介绍/程序运行/开发规范/对象树
开发语言·前端·c++·qt·学习
尘觉21 小时前
中秋节与 Spring Boot 的思考:一场开箱即用的团圆盛宴
java·spring boot·后端
间彧21 小时前
Seata分布式事务框架详解与项目实战
后端