拂拉氏头像
【知识讲解】 Linux信号的认识与使用封面图

【知识讲解】 Linux信号的认识与使用


目录

前言

Part1. 信号基础概念

Part2. 信号的产生方式

Part2.1. 键盘按键

Part2.2. 硬件异常

Part2.3. 主动发送信号

Part2.4. 软件条件触发

Part3. 信号在内核中的保存

Part3.1. 信号位图

Part3.2. 信号集操作函数

Part3.3. sigprocmask

Part4. sigaction

Part5. 信号处理的坑点

Part6. 信号 与 System V IPC

Part7. 结语


前言

  Linux下对于信号的了解是非常重要的,接下来来跟随小编的视角来看看吧。


let's go!!!!!!!!


Part1. 信号基础概念

信号是 Linux 下异步事件通知机制,和信号量无关。

• 本质:内核发给进程的简短通知,用来告知进程发生了某个事件。

• 特点:异步。进程正常运行时,信号随时可能抵达;进程不会立刻处理,先标记信号,等到合适时机(从内核态切回用户态前)再去处理。

• 类比:中断是CPU层面的异步通知;信号是进程层面的软件中断。


信号编号

信号用整数编号标识,Linux一共62个标准信号:

• 1 ~ 31:可靠信号(传统不可靠信号),不支持排队,同一个信号多次产生可能丢失;

• 34 ~ 64:实时信号,支持排队,不会丢失。


常用信号举例:SIGINT(2),对应终端 Ctrl + C。


收到信号后的三种处理方式

1. 默认处理(Default):操作系统内置行为,大部分是终止进程;

2. 自定义处理(Catch):注册信号处理函数,收到信号后执行我们自己写的回调;

3. 忽略处理(Ignore):收到信号直接丢弃,不做任何动作。


注意:SIGKILL(9)、SIGSTOP(19) 这两个信号不能捕获、不能忽略,只能执行默认行为。


信号处理函数类型
 

typedef void (*sighandler_t)(int);

• sighandler_t:信号处理函数类型,接收一个int参数(信号编号)

• signal 函数原型:
 

sighandler_t signal(int signum, sighandler_t handler);

• 参数:

◦ signum:要注册的信号编号

◦ handler:处理函数,可以填 SIG_DFL(恢复默认)、SIG_IGN(忽略)或者自定义函数指针

• 返回值:返回这个信号旧的处理函数指针。


小坑:signal 函数在不同UNIX体系行为有差异,工程代码优先使用 sigaction,更稳定可控。


Part2. 信号的产生方式

一共4大类产生途径:


Part2.1. 键盘按键

◦ Ctrl + C → SIGINT 终止进程

◦ Ctrl + \ → SIGQUIT 退出并生成core转储文件

◦ Ctrl + Z → SIGTSTP 暂停进程(放到后台)


Part2.2. 硬件异常

◦ 段错误 SIGSEGV:访问非法内存、野指针、栈溢出;MMU硬件检测到虚拟地址非法,内核发出信号

◦ 除零错误 SIGFPE:除法除数为0

◦ 总线错误 SIGBUS:非法地址对齐访问


Part2.3. 主动发送信号

◦ int raise(int sig);:给自己发信号

◦ void abort(void);:内部会触发 SIGABRT,终止进程,一般用来断言失败

◦ int kill(pid_t pid, int sig);:给指定pid的进程发送信号

pid > 0:发给pid对应的进程

pid = 0:发给调用进程所在进程组的所有进程

pid = -1:权限足够时,发给除init以外所有进程


Part2.4. 软件条件触发

◦ 定时器到期 SIGALRM、管道读端关闭写端收到 SIGPIPE 等。


补充:kill 函数名字有迷惑性,不是只能发杀死进程的信号,可以发送任意信号。


Part3. 信号在内核中的保存

Part3.1. 信号位图

每个进程PCB(task_struct)里面维护两张位图(bitmask),用一个整数/数组的每一位代表一个信号:

• 未决信号集(pending):某一位置1 → 这个信号已经产生,但是进程还没有处理;处理完毕后清零。

• 阻塞信号集(屏蔽字,mask):某一位置1 → 屏蔽这个信号。信号来了之后不会被处理,保留在pending位图里,等到解除屏蔽之后再处理。

逻辑判断:
信号到来 → 先看mask:
mask对应bit=0(不阻塞):合适时机立刻处理,pending清0
mask对应bit=1(阻塞):信号置在pending里挂起,暂时不处理


重点:不可靠信号不排队!
同一个不可靠信号在阻塞期间多次抵达,pending位只会置1一次,多次信号会丢失;实时信号支持排队。


Part3.2. 信号集操作函数

sigset_t 是信号位图类型,用来表示一组信号,配套函数:

int sigemptyset(sigset_t *set);    // 清空信号集,全部置0
int sigfillset(sigset_t *set);     // 填满信号集,全部置1
int sigaddset(sigset_t *set, int signum);  // 添加一个信号
int sigdelset(sigset_t *set, int signum);  // 删除一个信号
int sigismember(const sigset_t *set, int signum); // 判断信号是否在集合内

Part3.3. sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

• how:三种行为

◦ SIG_BLOCK:屏蔽,把set里的信号追加到原来的屏蔽字(mask |= set)

◦ SIG_UNBLOCK:解除屏蔽,把set里的信号从mask移除

◦ SIG_SETMASK:直接把mask替换成set的值

• oldset:出参,可以拿到修改之前旧的屏蔽字,方便后续恢复。


使用场景:临界区代码,我们不希望被信号打断 → 进入临界区屏蔽信号,执行完临界区解除屏蔽。


Part4. sigaction

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction {
    void (*sa_handler)(int);        // 老式信号处理函数
    void (*sa_sigaction)(int, siginfo_t *, void *); // 扩展版本,可以拿到发送方pid等信息
    sigset_t sa_mask;               // 【重点】执行当前信号处理函数期间,自动屏蔽的信号
    int sa_flags;
    void (*sa_restorer)(void);
};

• sa_mask:当我们正在跑这个信号回调的时候,自动屏蔽sa_mask里面的信号,防止信号嵌套打断当前handler;handler执行结束自动恢复。

• SA_SIGINFO:sa_flags开启这个标记,就会使用 sa_sigaction,拿到 siginfo_t,里面可以拿到发送信号的进程pid。


信号处理函数是在进程的用户态上下文执行,不是独立线程!handler执行的时候,主流程暂停。


Part5. 信号处理的坑点

1. 信号处理函数里面,不是所有函数都能调用!
只能调用可重入(异步信号安全)函数。printf、malloc、lock 这些非可重入函数禁止在信号handler调用,极易死锁、内存损坏。

2. 不可靠信号会丢失,不要依赖它做计数;需要可靠通知优先实时信号或者管道。

3. 信号只做通知,不要在handler写复杂业务逻辑。工程经典方案:信号handler里面只写一个字节写到管道,主循环epoll监听管道读端,把业务逻辑放到主循环处理(信号转IO事件)。

4. 子进程继承父进程的信号屏蔽字、信号处理方式;但是pending未决信号集不会继承。

5. fork之后子进程里面,继承信号处理函数;exec之后,所有捕获的信号重置为默认处理方式。


Part6. 信号 与 System V IPC

通信方式 核心特点 适用场景 
信号 异步、携带信息极少(只有信号编号),内核通知 异常通知、终止、暂停、定时器事件 
消息队列 面向消息,带类型,支持选择性读取 进程之间传递结构化数据 
信号量 计数器,用来做互斥、同步 保护临界资源,控制并发访问 

一句话区分:信号是通知事件;信号量是同步互斥工具,二者完全两码事


Part7. 结语

  这篇文章我们深入的知道了信号的相关知识,接下来,小编还会带来更多Linux相关的知识,敬请期待~

 最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

 最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2501_93971468/article/details/168982698

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--