linux 信号相关函数 二

信号集操作函数:

    sigset_t set ; 自定义信号集

    int sigemptyset(sigset_t* set); 清空信号集
        
    int sigfillset(sigset_t* set);  全部置一

    int sigaddset(sigset_t* set,int signum); 讲一个信号添加到集合中

    int sigdelset(sigset_t* set,int signum); 讲一个信号从集合中移除

    int sigismember(const sigset_t* set,int signum); 判断一个信号是否在集合中 在--》1; 不在——》0

设置信号屏蔽字和解除屏蔽:

    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);


    how:    SIG_BLOCK 设置阻塞 相当于用自定义集合和mask 做位或

        SIG_UNBLOCK 取消阻塞 相当于  mask & ~set

        SIG_SETMASK 用自定义set替换mask

    set: 自定义set

    oldset:旧有的 mask

查看未决信号集:


    int sigpending(sigset_t* set);

     set:传出的 未决信号集

// 设置信号屏蔽字
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

void sys_err(const char* str){
  perror(str);
  exit(1);
}

void print_set(sigset_t* set){
  int i;
  for(i=1;i<32;i++){
    if(sigismember(set,i)){
      putchar('1');

    }
    else{
      putchar('0');
    }
  }
  printf("\n");
}
int main(){


  sigset_t set,oldset,pedset;

  int ret =0;
  sigemptyset(&set);
  sigaddset(&set,SIGINT);
  sigaddset(&set,SIGQUIT);
  sigaddset(&set,SIGKILL);
  sigaddset(&set,SIGBUS);

  ret = sigprocmask(SIG_BLOCK,&set,&oldset);
  if(ret==-1){
    sys_err("sigprocmask error");
  }
  while(1){
  ret = sigpending(&pedset);
  if(ret==-1){
    sys_err("sigpending error");
  }
  print_set(&pedset);
  sleep(1);
  }
  return 0;
}

输出:

0000000000000000000000000000000
0000000000000000000000000000000
0000000000000000000000000000000
^C0100000000000000000000000000000
0100000000000000000000000000000
^\0110000000000000000000000000000
0110000000000000000000000000000
0110000000000000000000000000000
0110000000000000000000000000000
0110000000000000000000000000000
 

注册信号捕捉函数:  

注意 仅仅只是注册  真正抓信号的 是内核     

    typedef void (*sighandler_t)(int);

        sighandler_t signal(int signum, sighandler_t handler);

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string.h>
#include<signal.h>

void sys_err(const char* str){
  perror(str);
  exit(1);
}
void sig_catch(int signo){
  printf("catch you %d\n",signo);
}


int main(){

  signal(SIGINT,sig_catch);

  while(1);
  return 0;
}

        输出:

^Ccatch you 2
^Ccatch you 2
^Ccatch you 2

    sigaction();重点


     int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);


    act: 传入参数, 新的处理方式

    oldact:传出参数 旧的处理方式

    成功 :0

    失败: -1 errno

    eg:

        struct sigaction act;

             act.sa_handler = catch_child;   //设置回调函数 
                                                    
             sigemptyset(&act.sa_mask);     //设置捕捉函数执行期间屏蔽字

              act.sa_flags = 0;              //设置默认属性,本信号自动屏蔽

            sigaction(SIGCHLD,&act,NULL);  //注册信号捕捉函数

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<string.h>
#include<signal.h>

void sys_err(const char* str){
  perror(str);
  exit(1);
}
//回调函数
void sig_catch(int signo){
  if(signo==SIGINT){
  printf("catch you %d\n",signo);
  sleep(10);
  }
  else if(signo==SIGQUIT)
    printf("--------catch you %d\n",signo);
  return ;
}


int main(){


  struct sigaction act,oldact;
  act.sa_handler =  sig_catch;//设置回调函数
  sigemptyset(&(act.sa_mask));//清空sa_mask 只在 sig_catch工作时有效
  act.sa_flags = 0;// 默认值

  int ret = sigaction(SIGINT,&act,&oldact);
  if(ret==-1){
    sys_err("sigaction error");
 
 
  }
   ret = sigaction(SIGQUIT,&act,&oldact);
  
  if(ret==-1){
    sys_err("sigaction error");
  }
  while(1);
  return 0;
}

输出:

^Ccatch you 2
^C^C^C^C^C^C^Ccatch you 2
 


信号捕捉特性:

    1.捕捉函数执行期间 ,信号屏蔽字 由 mask--》sa_mask, 捕捉函数执行结束。 恢复回mask

    2.捕捉函数执行期间,本信号自动被屏蔽(sa_flgs =0)

    3.捕捉函数执行期间,被屏蔽的信号多次发送,解除屏蔽后只处理一次


借助信号完成子进程回收

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<signal.h>


void sys_err(const char* str){
  perror(str);
  exit(1);
}
//有子进程终止,发送SIGCHLD信号时,该函数会被内核回调
void catch_child(int signo){
  (void)signo;
  pid_t wpid;
  int status;
  while((wpid= waitpid(-1,&status,0))!=-1){     //循环回收防止僵尸进程出现
    if(WIFEXITED(status))
      printf("------------catch child id %d,ret=%d\n",wpid,WEXITSTATUS(status));

  }
  return;
}
int main(){
  pid_t pid;
  //设置阻塞 防止捕捉函数还未注册 信号到达
  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set,SIGCHLD);
  sigprocmask(SIG_BLOCK,&set,NULL);
  int i;
  for(i=0;i<15;++i){             //创建多个子进程
    if((pid=fork())==0){
      break;
    }
  }
  if(i==15){
    struct sigaction act;
    act.sa_handler = catch_child;   //设置回调函数
    sigemptyset(&act.sa_mask);     //设置捕捉函数执行期间屏蔽字
    act.sa_flags = 0;              //设置默认属性,本信号自动屏蔽
    sigaction(SIGCHLD,&act,NULL);  //注册信号捕捉函数
    //解除阻塞
    sigprocmask(SIG_UNBLOCK,&set,NULL);

    printf("i'm patent,pid=%d\n",getpid());
    while(1); //模拟父进程后续逻辑

  }
  else{
    printf("i'm child,pid=%d\n",getpid());
    return i;
  }
  return 0;
}

    

慢速系统调用中断:


系统调用分为两类:

    1.慢速系统调用: 可能会使进程永久阻塞的一类。如果在阻塞期间收到一个信号,该系统调用就被中断,不在继续执行;

    也可以设定系统调用是否重启。  如 read、write、wait....

    可修改  sa_flags 参数来设置被信号中断后系统调用是否重启。 SA_INTERRURT 不重启  。 SA_RESTART 重启

    2.其他系统调用: getpid( ) fork()

发布了78 篇原创文章 · 获赞 10 · 访问量 3821

猜你喜欢

转载自blog.csdn.net/weixin_44374280/article/details/104283051