0

0

【Linux】进程信号的发送和保存

看不見的法師

看不見的法師

发布时间:2025-06-21 13:04:01

|

514人浏览过

|

来源于php中文网

原创

一、信号发送

  1. 信号动作

通过指令man -7 signal查看信号的手册,可以找到普通信号发出后对应的操作、信号编号和详细描述信息。

【Linux】进程信号的发送和保存

  1. 信号发送的本质

普通信号的发送本质上是将信号写入进程的PCB结构体中的位图(pending位图)。这个位图对应着1到31号的普通信号,收到信号后将对应比特位置为1,表示信号已收到,然后PCB执行相应的工作。值得注意的是,如果连续发送普通信号,进程只会处理最后一次的信号,因为每次写入都是覆盖式的。

实时信号与普通信号类似,但它们使用的是结构体而非位图,信号被组织在队列中,遵循先入先出的规则。如果连续发送实时信号,进程会依次处理队列中的所有信号。

  1. Core Dump

在《进程控制》一文中,我们解释了wait函数的status参数,其中第7位是core dump标志。程序在运行过程中发生崩溃(如段错误、除零错误等)时,Core dump会记录程序崩溃瞬间的内存状态,包括寄存器的值、调用栈信息、全局变量和局部变量的值等。开发人员可以使用调试工具(如GDB)加载Core dump文件,分析这些信息以找出程序崩溃的原因。

可以通过ulimit -c 10240core文件的大小限制修改为10240字节。云服务器上通常默认core文件大小限制为0,出现错误时可能导致core文件迅速填满。我们可以根据需要修改其大小限制。生成的文件名为core.pid,其中pid是出错进程的pid。例如,假设test进程发生错误,其pid为12314,我们可以在GDB模式下输入gdb test core.12314来打印错误信息和原因。

二、信号的保存

  1. 前置概念

实际执行信号处理动作称为信号递达。信号从产生到递达之间的状态称为信号未决。被阻塞的信号会保持在未决状态,直到进程解除对此信号的阻塞,才会执行递达的动作。

【Linux】进程信号的发送和保存

  1. 阻塞信号

信号被阻塞时,会进入信号未决状态。阻塞功能通过一个31位的位图block实现,对应1到31号信号。当对应比特位为1时,表示该信号被阻塞,为0则表示不阻塞。如果信号被阻塞,则进入阻塞态;如果没有被阻塞,则进入未决状态。

  1. 保存信号

未决状态的作用是保存信号,通过位图pending实现。pendingblock一致,对应的下标和信号编号一一对应。当对应比特位为1时,表示该信号处于未决状态,为0则表示信号已递达。实际上,blockpending都用于保存信号,但由于有两个位图,我们分开讨论。

  1. 信号递达

信号递达后,会执行相应的行为,包括SIG_DFL(默认处理动作)、SIG_IGN(忽略)和自定义处理sighandler

【Linux】进程信号的发送和保存

  1. 总结

【Linux】进程信号的发送和保存

一个信号首先经过block,如果block为0,则来到pending,如果pending为0,则来到handler执行动作。9号和19号信号是特例,它们不能被阻塞和保存,一旦发出直接执行handler,对应的行为只能是默认动作终止和暂停。

SLStuan手拉手团购程序(仿拉手网)
SLStuan手拉手团购程序(仿拉手网)

手拉手团购系统是一套Groupon模式的开源团购程序,是骏商网络(dream3.cn)旗下开发的一套仿拉手网团购程序,是国内首套采用ASP+MSSQL开发的团购程序,安装超简,功能超全面,在保留手拉手团购系统版权的前提下,允许所有用户永久免费使用、永久免费升级。手拉手团购系统内置多种主流在线支付接口,所有网银用户均可无障碍支付;短信发送团购券和实物团购快递发货等。 SLStuan手拉手团购程序 v

下载

三、信号集操作函数

信号集操作函数用于操作信号集,sigset_t操作系统提供的数据类型,用于描述位图。以下是信号集操作函数:

#include 
int sigemptyset(sigset_t *set); // 将位图全部设置为0
int sigfillset(sigset_t *set); // 将位图全部设置为1
int sigaddset(sigset_t *set, int signo); // 将位图中的某一位设置为1
int sigdelset(sigset_t *set, int signo); // 将位图中的某一位设置为0
int sigismember(const sigset_t *set, int signo); // 判断一个信号是否在信号集中,不在返回0,在返回1,出错返回-1
  1. 设置block位图

sigprocmask是一个重要的系统调用,用于检查和修改进程的信号掩码(阻塞信号集)。

#include 
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

返回值:成功返回0,失败返回-1。

how参数指定对信号掩码的操作方式:

how取值 含义 示例说明
SIG_BLOCK 将set所指向的信号集中的信号添加到当前的信号掩码中,即阻塞set中的信号 若当前信号掩码已阻塞SIGINT,使用SIG_BLOCK并传入包含SIGTERM的信号集,SIGTERM也会被阻塞
SIG_UNBLOCK 从当前的信号掩码中移除set所指向的信号集中的信号,即解除对set中信号的阻塞 若当前信号掩码阻塞了SIGINT和SIGTERM,使用SIG_UNBLOCK并传入包含SIGINT的信号集,SIGINT信号的阻塞状态将被解除
SIG_SETMASK 将当前的信号掩码设置为set所指向的信号集,覆盖原来的信号掩码 若原信号掩码阻塞SIGINT,使用SIG_SETMASK并传入包含SIGTERM的信号集,信号掩码将只阻塞SIGTERM

set参数指向一个sigset_t类型的信号集,包含要操作的信号。如果how的值为SIG_BLOCKSIG_UNBLOCKset表示要添加或移除的信号集;如果how的值为SIG_SETMASKset表示要设置的新信号掩码。如果该参数为NULL,则不改变当前的信号掩码,仅获取当前信号掩码,此时oset不能为NULL

oset参数指向一个sigset_t类型的信号集,用于存储调用sigprocmask之前的信号掩码。如果不需要保存旧的信号掩码,可以将该参数设置为NULL

  1. 设置pending位图

sigpending用于获取进程当前未决信号集。

#include 
int sigpending(sigset_t *set);

返回值:成功返回0,失败返回-1。

set参数用于存储当前进程中处于未决状态(即已发送但由于被阻塞而尚未被处理)的信号集。

  1. 设置handler行为

信号处理行为有三种情况:默认、忽略和自定义。自定义处理可以通过signal函数实现,此前已有介绍,不再赘述。

四、验证信号保存行为

#include 
#include 
#include 
using namespace std;

// 打印出位图
void PrintPending(const sigset_t &pset) {
    for(int i = 31; i >= 1; i--) {
        cout << (sigismember(&pset, i) ? 1 : 0);
    }
    cout << endl;
}

// 信号处理函数
void handler(int sig) {
    cout << "Caught signal " << sig << endl;
}

int main() {
    sigset_t newmask, oldmask, pendmask;

    // 初始化信号集
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGINT);

    // 阻塞SIGINT信号
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    // 打印当前未决信号集
    while(1) {
        sigpending(&pendmask);
        PrintPending(pendmask);
        sleep(1);
    }

    // 解除SIGINT信号的阻塞
    sigprocmask(SIG_SETMASK, &oldmask, NULL);

    return 0;
}

在3秒后按下ctrl+c,捕捉信号函数不会工作,说明信号被阻塞了。15秒后自动解除阻塞,立即打印出handler函数定义要打印的信息,再按ctrl+c就正常执行handler行为。

【Linux】进程信号的发送和保存

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

306

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

232

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

437

2024.03.01

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

190

2025.07.04

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Rust 教程
Rust 教程

共28课时 | 4.6万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.5万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号