一、信号产生、处理、分类
二、signal信号处理机制
三、sigaction 高级版的信号处理函数
四、全程阻塞 sigprocmask
五、信号相关函数
1.kill函数
2.sleep函数
3.alarm函数
4.pause函数
六、计时器
信号就像古代战场上打仗,摇什么旗子摆什么阵。双方已经约定好。能不使用信号就不要使用信号,因为是异步。
信号是硬件中断的软件模拟(软中断)。
kill -1 查看信号列表
man 7 signal 主要查看信号行为
需要掌握:1到31号信号。
2 SIGINT ctrl c siginterupt
3 SIGQUIT ctrl \
9 SIGKILL kill -9 夺命信号,大王!不能捕捉也不能忽略
19 SIGSTOP ctrl z 夺命信号,小王!不能捕捉也不能忽略
-------------------------------------------------------------------------------------------------------------------------------------------------------------
一、信号产生、处理、分类:
信号的产生:
信号的生成来自内核,让内核生成信号的请求来自3个地方:
1.用户:用户能够通过输入CTRL+c、Ctrl+\,或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;
2.内核:当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等;
3.进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
信号的处理:
进程接收到信号以后,可以有如下3种选择进行处理:
1.接收默认处理:接收默认处理的进程通常会导致进程本身消亡。例如连接到终端的进程,用户按下CTRL+c,将导致内核向进程发送 一个SIGINT的信号,进程如果不对该信号做特殊的处理,系统将采用默认的方式处理该信号,即终止进程的执行;
2.捕捉信号并处理:进程可以事先注册信号处理函数,当接收到信号时,由信号处理函数自动捕捉并且处理信号。
9号信号(kill -9)和19号信号(ctrl z)不能被捕捉也不能被忽略。
进程接收到这两个信号后,只能接受系统的默认处理,即终止进程.
钩子:回调函数
默认处理的话,一般会把程序搞崩溃。
进程事先注册信号处理函数。当信号来了的时候
信号的分类:
同步信号:由进程的某个操作产生的信号,例如除0、内存访问违规;
异步信号:由像用户击键这样的进程外部事件产生的信号,再如,ctrl+z.
二、signal信号处理机制(最基本的信号处理函数)
可以使用函数signal()注册一个信号处理函数。原型为:
typedef void (*
sighandler_t)(int);
//函数指针。定义一种sighandler_t的类型。这个类型是指向某种函数的指针。这个函数以int型为参
数,并返回void类型。
sighandler_t
signal(
int signum, sighandler_t
handler);
//信号处理函数。signum是要捕捉的信号。handler是函数指针,也就是函数的地
址,
而函数名就是该函数所占内存的首地址。所以可以直接传入函数名。该
参数也可
以是SIG_DFL或SIG_IGN。若为SIG_DFL:表示交由系统缺省处理,相当于白注册
了。若为:SIG_IGN,表示忽略该信号。
例1:signal的使用,捕捉ctrl+c产生的信号
#include <signal.h> //signal()的头函数
void sig_func(int sig){
//信号处理函数,sig是传进去的几号信号。信号处理函数,必须固定这种格式。因为这是内核
printf("sig=%d is coming\n",sig);
调用的。
内核只传给我一个参数让我用。在信号处理函数中,如果想使用别的参数,只有一种
方法:使用全局变量。
}
int main(){
if(
signal(SIGINT,sig_func)==SIG_ERR){
//返回值是一个函数指针 。SIGINT就是2。
perror("signal");
}
while(1);
//这样就可以在函数的执行过程中给函数发信号了。函数执行到某一句时给他发信号,这是跳转
过去执行信号。执行完成信号后,回到跳转的那一句,接着跑。比如在这一句ctrl c之后,先去
执行sif_func,执行完之后会继续循环。
return 0;
}
例2:忽略信号的例子
int main(){
signal(
SIGINT,
SIG_IGN);
//当输入2号信号时,内核接受到以后不做任何处理。
while(1);
return 0;
signal(
SIGINT,SIG_DFL);
//到这个地方又不想忽略了。
}
例3:signal的重入
2号信号正在执行。2号又来了,怎么办?不能重入。
2号信号正在执行,3号又来了,怎么办?可以重入。
2号在执行,3号来了打断,此时有来了个2号,则后面的2号不能重入。
内核存储:
按一次ctrl+c,然后在ctrl+c处理函数执行过程中连续多次按ctrl+c。则后面多次ctrl+c只执行一次处理函数,也就是总共执行两次处理函数。原理:
内核针对信号,存储每个信号只有一个位置。存放在信号队列中。第一个2号信号来了之后,队列中对应位置立即从0变为1,然后内核看到有1,就拿走并执行。此时来了第二个2号信号,发现对应位置是0,于是填上1。之后又来了多个2号信号。因为内核还在执行第一个2号信号。所以第二个2号信号填上的1没有拿走,对应的位置还是1.这时后面的多个2号信号只能在对应位置置1(不变)。等第一个处理程序处理完之后,会把1拿走,去执行第二次。
#include <signal.h>
void
sig_func(int sig){
printf("before:sig=%d is coming\n",sig);
sleep(3);
printf("after:sig=%d is coming\n",sig);
}
int main(){
if(
signal(SIGINT,sig_func)==SIG_ERR){
//2号信号:ctrl c
perror("signal");
}
if(
signal(SIG