进程间通信:信号

本文详细介绍了Linux中的信号机制,包括信号的产生、处理和分类,重点讲解了signal和sigaction两种信号处理函数,以及相关函数如kill、sleep、alarm和pause的使用。还介绍了阻塞信号的处理函数sigprocmask,以及如何使用getitimer和setitimer设置计时器。通过对这些函数的深入理解,可以更好地进行进程间的通信和控制。
摘要由CSDN通过智能技术生成
一、信号产生、处理、分类
二、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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值