Linux信号

Linux信号

  • 00.什么是信号?

1.信号顾名思义,就是平时用来传递信息的一种手段,如小明的妈妈:“小明回家吃饭了!”,其实这就是一种信号,当小明听到了这句话的时候,就知道要回家吃饭了(要不然估计又是一顿)。
2.正如上面所说Linux信号也是一样的,发送信号给某个进程,当这个进程收到了信号,那么收到这个信号的进程就会按照该信号的处理方式去做出相应的处理动作。
3.结合上篇博客,可以知道,信号也是进程间通信的一种手段。

  • 01.Linux下有哪些信号?

1.用kill -l 来查看linux下所有信号
这里写图片描述
2.通过man -7 signal 来查看对这些信号的描述和处理动作
这里写图片描述

  • 02.Linux信号产生方式和信号处理方式


-1.如图

这里写图片描述

1.键入信号:

ctrl -\
这里写图片描述
解释说明:其中core dump文件是记录执行该信号处理函数前一个程序的状态,通常们可以通过ulimit -a 来查看当前对core dump定义,一般情况下,core dump文件大小为0,也就是不生成core dump文件,当时可以通过参数进行修改。如图
这里写图片描述
此时运行一个死循环程序就会产生一个core dump文件,
这里写图片描述

1.1.上述涉及到信号在PCB(内核)中的表示,所以请看下图

这里写图片描述
其实就是上图所示的一样,每个进程对信号都一个自己独立的处理方式,而对信号的处理方式都在PCB中的某个字段上,其中有二个”位图”(sigset_t结构信号集),记录着该进程对信号的阻塞,未决,还有一个函数指针用来指向信号处理函数。其中特别值得注意的是,忽略和阻塞是不一样的,阻塞是不会递答的,而忽略则是一种处理信号的方式,即在抵达之后,在handler中找到处理方式。


2.调用系统函数发送型号给进程

2.1系统API是kill 命令
这里写图片描述
2.2看一下实例:通过用kill 发送SIGINT指令使其死循环终止进程。
这里写图片描述

3.由软件产生的信号

(1)前面博客讲到了管道,当一个管道的读端关闭在尝试去写,那么会产生一个SIGPIPE信号。
(2)而在一个子进程结束后,会向父进程发送SIGCHLD信号
(3)alarm函数,即闹钟函数,在其设置时间到达时,会尝试发送以SIGALRM信号,默认终止程序。
这里写图片描述
示例代码:

int main()
{

    std::cout<<"设置一个3s的闹钟!"<<std::endl;   

    alarm(3);

    for(;;)
    {
        std::cout<<"程序在运行中 !"<<std::endl;
        sleep(1);
    }
}

//程序执行结果
[skin@bogon Git]$ ./a.out 
设置一个3s的闹钟!
程序在运行中 !
程序在运行中 !
程序在运行中 !
闹钟
[skin@bogon Git]$ 

  • 03.信号的设置
  • -

1.信号集设置的API接口及其描述
这里写图片描述
2.纸上得来终觉浅,写个代码就全明白了

5 void PrintSigSet(sigset_t set)
  6 {
  7     //打印1-31号信号
  8     std::cout<<"阻塞集 :\n";
  9     for(size_t i=1;i<32;++i)
 10     {   
 11         if(sigismember(&set,i))
 12             std::cout<<"1 ";
 13         else
 14             std::cout<<"0 ";
 15     }
 16     std::cout<<std::endl;
 17     
 18     
 19     std::cout<<"未决集 :\n";
 20     sigpending(&set);
 21     for(size_t i=1;i<32;++i)
 22     {   
 23         if(sigismember(&set,i))
 24             std::cout<<"1 ";
 25         else
 26             std::cout<<"0 ";
 27     }
 28     std::cout<<std::endl;
 29     std::cout<<std::endl;
 30  
 31 }
 32 
 33 int main()
 34 {
 35     //0.定义
 36     sigset_t newset,oldset;
 37     //1.初始话
 38     sigemptyset(&newset);
 39     //2.将SIGINT信号添加到set中
 40     sigaddset(&newset,SIGINT);
 41     //3.设置SIGINT到屏蔽字中
 42     sigprocmask(SIG_BLOCK,&newset,&oldset);
 43     //4.测试ctrl-c是否被阻塞
 44     while(1)
 45     {
 46         PrintSigSet(newset);
 47         sleep(1);
 48     }
 49     
 50     return 0;
 51 }  

//程序执行结果
这里写图片描述

  • 04.信号的捕捉

1.如图
这里写图片描述
2.信号捕捉API
这里写图片描述

1.sigaction函数是用来处理实时信号的,可以修改信号的处理函数,从而达到捕捉的效果。
2.其中signum表示处理信号的编号,act表示你想对信号怎样处理,即其信号处理函数的定义,oldact则表示的是原有的信号处理动作,可以用它来进行原来信号处理的行为,如果为NULL则表示不关心其动作。
3.sigaction结构中的sa_handler字段用来表示处理动作,sa_mask用来说明在处理此信号是应该还要屏蔽那些信号,sa_flag是一些其他选项。
4.信号处理过程中,或者说在信号处理函数中,该信号会自动加入信号屏蔽中,等处理完成后在回复原来方式。否则如果不加入屏蔽字,那么这个处理函数如果不是可重入的,就会导致一些问题。
5.示例代码:

void sighandler(int signo)                                                                                                                    
 37 {
 38     (void)signo;
 39     std::cout<<"子进程: "<<waitpid(-1,NULL,0)<<" 退出时发送的SIGCHLD信号 !"<<std::endl;
 40     exit(-1);
 41 }
 42 
 43 int main()
 44 {
 45     //0.定义
 46     struct sigaction act,oldact ;
 47     //1.初始化act
 48     act.sa_handler = sighandler;
 49     act.sa_flags =0;    
 50     sigaction(SIGCHLD,&act,&oldact);
 51     //2.fork创建子进程
 52     
 53     pid_t pid =vfork();
 54     if(pid<0)
 55         return -1;
 56     if(pid==0)
 57     {
 58         std::cout<<"子进程: "<<getpid()<<" 执行完毕!"<<std::endl;
 59         exit(0);
 60     }
 61     else
 62     {
 63     }
 64     
 65 
 66     return 0;
 67 }

//程序执行结果
[skin@bogon Git]$ ./a.out 
子进程: 12912 执行完毕!
子进程: 12912 退出时发送的SIGCHLD信号 !
  • 05.其他相关问题
  1. signal 函数也是进行捕捉
    这里写图片描述
    signum:信号编号
    handler:处理信号函数
    2.上面提到可重入函数:一段代码同一时刻有多个执行流进行执行,而不会影响其结果的正确性,称为可重入的,否则就是不可重入的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值