1.信号
1.1 信号编号
- 在 Linux 系统中,可以通过 kill -l 命令查看信号的编号;
- 前31个信号是软件工程师所使用的,后33个是嵌入式工程师所使用的信号;
1.2 常用的信号(有快捷键的信号)
- ctrl+c :触发 SIGINT 信号;
- ctrl+z :触发 SIGQUIT 信号;
- ctrl+\ :触发 SIGTSTP 信号;
1.3 信号产生的方式
- 1.终端组合按键产生信号(三种):ctrl+c、ctrl+\、ctrl+z ;
- 2.函数产生信号: kill(pid_t, signo) 函数用来给任意进程发送任意信号 、 raise(signo) 函数用来给调用函数进程发送任意信号 、 abort(void) 函数用来给当前调用进程发送指定信号 ;
- 3.硬件异常产生信号:段错误(非法操作内存触发 SIGSEGV)、浮点数例外(CPU非法计算,如除零错误,运算错误触发 SIGFPE);
- 4.软条件产生信号:定时器产生信号(alarm函数,触发 SIGALRM)、管道产生信号(SIGPIPE)。
1.4 使用kill函数杀死进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc, char** argv)
{
if(argc < 3)
{
printf("Too Less Argvs...\n");
exit(0);
}
kill(atoi(argv[2]), atoi(argv[1]));
return 0;
}
1.5 使用 alarm 函数定时发送 SIGALRM 信号
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int main()
{
int n_count = 0;
alarm(1);
while(1)
printf("count=%d\n", ++n_count);
return 0;
}
1.6 pause 函数
- 该函数会挂起当前进程,pause函数会期待一个任意信号,只要有信号产生,pause函数就会唤醒当前进程;
- 当前默认 SIGALRM 信号会导致进程终止,只要将该信号的终止进程功能被忽略掉,即可配合 pause 函数与 alarm 函数完成 sleep 函数的实现;
1.7 任意信号都有三大行为五大动作
- 1.三大行为
- 1.默认行为: DFL ;
- 2.忽略行为: IGN ;
- 3.自定义(捕捉)行为: ACTION ;
- 2.五大动作
- 1.TERM(杀死进程)
- 2.CORE(杀死进程并核心转储)
- 3.IGN(什么也不干,进程不会被终止)
- 4.STOP(进程被挂起)
- 5.COUNT(进程被唤醒继续执行)
1.8 注意事项
- 1.五大动作是五种默认行为的信号处理动作;
- 2.忽略行为会忽略信号,导致信号失去作用;
- 3.捕捉行为是让信号失去原有作用,并赋予它新的工作;
- 4.无法被忽略或捕捉或阻塞的两个信号,这两个信号直接为内核服务,只要发送必然递达;除了这两个信号之外,其他所有信号都能被处理,失去原有作用;
1.9 信号的传递流程
- 1.组合键输入
- 2.线路规程:识别处理组合按键
- 3.通知内核向前台进程发送一个 SIGINT 信号(send SIGINT)
- 4.信号通过内核穿过 PCB(PCB有两个过滤管,一个是未决信号集(全0信号集),一个是屏蔽字(阻塞信号集)) 的两个信号集进入选择处理(handler),信号到达处理流程则未决信号集对应位置为0;
- 5.处理完成。
1.10 注意
- 信号首先通过内核的PCB的未决信号集,判断对应位置的信号是1还是0,为1则新来的信号被丢弃,为0则通过(被丢弃的原因是信号不支持排队);再判断屏蔽字,屏蔽字对应位置为0则允许通过,为1则阻塞;
- 未决态信号:信号通过了未决信号集但还没有进入信号处理流程
- 递达态信号:只要信号进入处理流程,则该信号为递达态
- 未决信号集是通过内核负责使用和反转的
- 用户可以自定义屏蔽字决定阻塞哪些信号
1.11 使用 sigprocmask 函数对屏蔽字进行替换
- 1.sigprocmask 函数
- 第一个参数:方式,有 SIG_BLOCK 、 SIG_UNBLOCK 、 SIG_SETMASK 三种方式,第一种是使用进程默认屏蔽字与自己设定的屏蔽字按位或得到当前进程的屏蔽字,第二种方式是取消设置的屏蔽字,第三种是直接替换屏蔽字;
- 第二个参数是新的屏蔽字集合;
- 第三个参数是原来的屏蔽字的集合;
- 2.使用 sigprocmask 函数
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int main()
{
sigset_t new_set, old_set;
sigempty(&new_set);
sigaddset(&new_set, SIGINT);
sigprocmask(SIG_BLOCK, &new_set, &old_set);
while(1);
return 0;
}
- 3.上述代码的功能是将组合按键产生的 SIGINT 信号屏蔽掉了,使用的原理是通过新的信号集与系统默认的信号集进行位或操作的到新的信号集,进而对信号进行屏蔽;