Linux 多线程 + 信号,统一屏蔽哪些信号?什么是异步信号,同步信号?

一、先区分两大类信号

Linux 里的信号,工程上通常分:

类型 特点
异步信号(Asynchronous Signal) 外部事件产生
同步信号(Synchronous Signal) 当前线程执行错误导致

这是最重要的分类。

二、什么是异步信号

所谓:异步

意思是:信号什么时候来,和当前线程执行什么代码没直接关系。

典型异步信号

信号 来源
SIGINT Ctrl+C
SIGTERM kill pid
SIGQUIT Ctrl+\
SIGHUP 终端断开
SIGUSR1 用户自定义
SIGUSR2 用户自定义
SIGCHLD 子进程退出
SIGALRM 定时器
SIGPIPE 管道断开(有争议,半同步)

特点

这些信号:任何时刻都可能来

所以:

最适合:signal-thread + sigwait()

统一处理。

三、什么是同步信号

同步信号:当前线程执行某条指令时立即产生。

即:错误由当前线程自己造成

典型同步信号

信号 原因
SIGSEGV 非法内存访问
SIGBUS 总线错误
SIGILL 非法指令
SIGFPE 除0、浮点异常
SIGTRAP 调试断点

特点

这些信号:必须发给出错线程

因为:CPU 当前执行流已经出错。

四、工程里通常怎么屏蔽信号

标准模型

1)main线程启动后:

先屏蔽一批异步信号

例如:

复制代码
sigset_t set;

sigemptyset(&set);

sigaddset(&set, SIGINT);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGQUIT);

pthread_sigmask(SIG_BLOCK, &set, NULL);

五、为什么 main 线程先 block

因为:

后面创建的新线程:会继承父线程 signal mask

这是 Linux/POSIX 规定。

所以,这样做后:所有 worker thread 默认都 block 这些信号。

避免:信号随机打断工作线程

六、然后创建 signal-thread (信号处理线程,专门处理信号)

例如:pthread_create(&tid, NULL, signal_thread, NULL);

七、signal-thread 干什么

它专门:sigwait()

等待信号。

例如:

复制代码
void *signal_thread(void *arg)
{
    int sig;

    while (1)
    {
        sigwait(&set, &sig);

        switch(sig)
        {
            case SIGINT:
            case SIGTERM:
                g_stop = 1;
                break;
        }
    }
}

工作线程:

复制代码
while (!g_stop)
{
    工作...
}

然后:
停止接收新任务
保存数据
flush 文件
关闭 socket
回收资源

八、为什么 sigwait 能收到 block 的信号

因为:sigwait() 本质上就是: "同步地取走 pending signal"

所以,信号必须:先 block

否则:内核会直接异步递送 signal。sigwait() 就抢不到了。

九、一般统一屏蔽哪些信号

工程里通常屏蔽:

常见统一管理信号

信号 用途
SIGINT Ctrl+C
SIGTERM 优雅退出
SIGHUP 重载配置
SIGQUIT 退出+core
SIGUSR1 用户控制
SIGUSR2 用户控制
SIGCHLD 子进程状态变化
SIGPIPE 管道断开

十、SIGPIPE 为什么常 block

这是服务器开发经典问题。

例如:客户端断开 , 线程:write(socket, ...)

默认:内核发 SIGPIPE

默认动作:终止进程 ,这太危险。

所以服务器通常:

方案1(最常见)

直接忽略:signal(SIGPIPE, SIG_IGN);

方案2

统一 block。

十一、哪些信号通常不 block

同步异常信号

通常:不能靠 sigwait 处理

包括:

信号
SIGSEGV
SIGBUS
SIGILL
SIGFPE

原因:

这些信号:必须立即打断出错线程

否则, CPU 都无法继续执行。

十二、为什么不能用 signal-thread 处理 SIGSEGV

例如:

线程:

*p = 100;

CPU:

page fault

此时:

当前线程:已经无法继续执行

所以,必须:立即进入 SIGSEGV handler

而不是:排队等 signal-thread

十三、Linux 实际工程经验

通常:

signal-thread 只处理:"进程控制类异步信号"

例如:

信号 用途
SIGTERM 退出
SIGINT Ctrl+C
SIGHUP reload
SIGUSR1 控制
SIGUSR2 控制
SIGCHLD 子进程管理

而同步异常:

通常:

  • 不特殊处理
  • 或只打印 crash log
  • 然后整个进程退出

十四、真正的大型程序会怎么做

例如:

  • JVM
  • Redis
  • Nginx
  • PostgreSQL

通常:

异步信号

signal-thread:统一管理

崩溃信号

注册:sigaction(SIGSEGV, ...)

用于:

  • backtrace
  • dump
  • core
  • crash log

然后:abort / exit

十五、一个非常重要的总结

异步信号 特点:来自外部事件

工程处理:signal-thread + sigwait

同步信号 特点:当前线程执行错误

工程处理:只能由出错线程处理

通常:记录崩溃信息后退出

十六、一个"工业级口诀"


异步信号:

block + sigwait + signal-thread

同步异常:

fault thread only

SIGSEGV:

crash fast, don't recover 迅速崩溃,不要恢复

这是 Linux/UNIX 世界非常核心的哲学。

相关推荐
win水1 小时前
七、Linux 进程
linux·进程
淼淼爱喝水1 小时前
Ansible 中 handler 与 notify 的作用与使用详解
linux·网络·apache·playbook
Hello_Embed1 小时前
libmodbus 源码分析
笔记·stm32·单片机·嵌入式·ai编程
sbjdhjd1 小时前
Docker 安全优化实战手册(企业级硬核版)
linux·运维·docker·云原生·容器·eureka·kubernetes
小周技术驿站1 小时前
Linux 基础命令详解
linux·前端·chrome·ubuntu·centos
kdxiaojie1 小时前
U-Boot分析【学习笔记】(7)
linux·笔记·学习
www.021 小时前
通过 SSH 隧道将 GPT 调教为服务器专属 Agent(个人记录)
linux·服务器·vscode·gpt·大模型·ssh·api转发
张小姐的猫1 小时前
【Linux】多线程(中)—— 线程控制接口 | 线程库 | 线程局部存储
linux·运维·服务器
脆皮炸鸡7551 小时前
大山之二:文件系统(Ext系列)
linux·开发语言·经验分享·学习方法