1.信号

   信号主要用来通知进程发生了异步事件,而不会给进程传递任何数据。信号总共有62个,前32个被称为普通信号,34-64被称为实时信号。通常只关心普通信号。

2.信号的产生

  1> 键盘

       通过组合键发送一个信号,一定是给前台进程的。例如ctrl+c

  2>用系统函数发送信号

      可以给指定进程发送信号,例如kill命令用kill()函数实现,abort函数是当前进程接收到信号而异常终止。raise自己给自己发送信号。

  3>由软件条件产生

    alarm(时间数),当alarm完成后直接终止进程。

3.信号的处理

   1>忽略

   2>执行信号默认处理方式

   3>自定义方式:捕捉信号

     使用sighandler_t signal(int signum, sighandler_t handler);

     注:第一个参数是哪个信号,第二个参数是捕捉信号的函数名

4.阻塞信号

   1>实际执行信号处理动作称为信号递达。

   2>信号从产生到递达之间的状态称为信号未决。

 进程可以选择阻塞某个信号,被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。(忽略与阻塞不同,忽略是在信号递达之后)

信号不是立即处理的,是在一个合适的点上处理的。除了9号信号。

信号在内核中表示示意图:

wKioL1crCSrAeQV0AAA2DKpcuS0363.png

一个信号没有pending,可以被block。block与pending没有关系。

信号代码举例:

  1 #include<stdio.h>
  2 #include<signal.h>
  3 void show(sigset_t* sig_pending)//展示未决的信号
  4 {
  5   int i=1;
  6   for(i=1;i<32;++i)
  7   {
  8     if(sigismember(sig_pending,i))
  9     {
 10           printf("1");
 11     }
 12 
 13    else
 14   {
 15         printf("0");
 16    }
 17 
 18 
 19    }
 20 printf("\n");
 21 }
 22 
 23 void handler(int sig)//捕捉递达的信号
 24 {
 25   printf("I  see you! %d\n",sig);
 26 
 27 
 28  }
 29 
 30 int main()
 31 {
 32      sigset_t sig_mask;
 33      sigset_t sig_old;
 34      sigset_t sig_pending;
 35      sigemptyset(&sig_mask);
 36      sigemptyset(&sig_old);
 37      sigemptyset(&sig_pending);
 38      sigaddset(&sig_mask,SIGINT);//将2号信号放入信号集中阻塞
 39      sigprocmask(SIG_SETMASK,&sig_mask,&sig_old);
 40      int count=10;
 41     signal(SIGINT,handler);
 42      while(1)
 43      {
 44         sigpending(&sig_pending);//获取当前进程信号集,与pending有关
 45         show(&sig_pending);
 46         sleep(1);
 47        if(count<0)
 48         {
 49           sigprocmask(SIG_SETMASK,&sig_old,NULL);//恢复2号信号
 50         }
 51         count--;
 52      }
 53    return 0;
 54 }

wKioL1crC-XhlvftAABAKG9JfMI699.png

用户模式与内核模式切换关于信号

wKioL1crFHiCYaINAAHJkHV48wY922.png

5.捕捉信号

  1>sigaction

#include <signal.h>

int sigaction(int signo, const struct sigaction *act, struct

sigaction *oact);

sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则

返回- 1。signo是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。

若oact指针非 空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结

构体

.wKiom1crGSbCZQs6AACFsajhi2I104.png

  1 #include<stdio.h>
  2 #include<signal.h>
  3 #include<string.h>
  4 void handler(int sig)
  5 {
  6   printf("I am that signal...%d\n",sig);
  7 } 
  8 int main()
  9 {
 10    struct sigaction old;
 11    struct sigaction act;
 12    act.sa_handler=handler;//自定义处理信号动作
 13    act.sa_flags=0;
 14    sigemptyset(&act.sa_mask);
 15    memset(&old,'\0',sizeof(old));
 16    sigaction(SIGINT,&act,&old);对2号信号设置
 17     while(1)
 18     {
 19      printf("I am waiting  a signal....\n");
 20      sleep(2);
 21      }
 22      return 0;
 23 }

 2>pause

int pause(void);

pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终

止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause

不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为

EINTR, 所以pause只有出错的返回值(想想以前还学过什么函数只有出错返回值?)。错误码

EINTR表 示“被信号中断”。

下面我们用alarm和pause实现sleep(3)函数,称为mysleep。

  1 #include<stdio.h>

  2 #include<signal.h>

  3 #include<string.h>

  4 void handler(int sig)

  5 {

  6 //donothing

  7 }

  8 void  my_sleep(int time)

  9 {

 10  struct sigaction act,old;

 11  act.sa_handler=handler;

 12  act.sa_flags=0;

 13  sigemptyset(&act.sa_mask);

 14  sigaction(SIGALRM,&act,&old);

 15  alarm(time);//设置闹钟

 16  pause();

 17  int ret=alarm(0);//清理闹钟

 18  sigaction(SIGALRM,&old,NULL);恢复信号

 19  

 20 }

 21 int main()

 22 {

 23     while(1)

 26      {

 27      printf("I am waiting  a signal....\n");

 28      my_sleep(5);

 29      }

 30      return 0;

 31 } 

 程序结果:每隔5秒打印一次信息,相当于调用了sleep()函数。


 程序分析:

   

1. main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数

sig_alrm。

2. 调用alarm(nsecs)设定闹钟。

3. 调用pause等待,内核切换到别的进程运行。

4. nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程。

5. 从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数

是sig_alrm。

6. 切换到用户态执行sig_alrm函数,进入sig_alrm函数时SIGALRM信号被自动屏蔽,

从sig_alrm函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入 内核,再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数)。

7. pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号

以前的处理 动作。