信号(2)

(接上篇信号(1))

四 信号集

  以一个二进制位代表一个信号,考虑到扩展的问题,因此用一个很大的整数代表多个信号,这个很大的整数就是信号集,信号集的类型 sigset_t.
  集合必须提供的功能:
  增加元素、删除元素、查找元素、取出元素
  信号集的功能函数:
  sigemptyset() - 清空全部信号(二进制位置0)
  sigfillset() - 填满全部信号(二进制位置1)
  sigaddset() - 增加一个信号
  sigdelset() - 删除一个信号
  sigismember()- 判断是否有某个信号(有返回1)

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

int main(){
    printf("size=%d\n",sizeof(sigset_t));
    sigset_t set;
    sigemptyset(&set); 
    printf("set=%d\n",set);
    sigaddset(&set,2); 
    printf("set=%d\n",set);
    sigaddset(&set,3);
    printf("set=%d\n",set);
    sigaddset(&set,10);
    printf("set=%d\n",set);
    sigdelset(&set,3);
    printf("set=%d\n",set);
    if(sigismember(&set,2)){
      printf("信号2存在\n");
    }
}

五 信号屏蔽

  在执行某些关键代码时,不希望代码被信号中断。此时可以使用信号屏蔽,信号屏蔽不是阻止信号的到来,而是延后信号的处理(信号来了但不处理)。解除信号屏蔽以后再处理来过的信号。
  设置信号屏蔽字函数:
  sigprocmask(int how,sigset_t* new,sigset_t* old)
  参数how是屏蔽方式,有三种:
SIG_BLOCK - 相当于加法在原有的基础加上新的
  a b c + c d e -> a b c d e
SIG_UNBLOCK - 相当于减法在原有的基础上减去新的
  a b c - c d e -> a b
SIG_SETMASK - 重新设置,与原有的无关
  a b c c d e -> c d e
  一般使用SIG_SETMASK
  参数new是新的屏蔽信号集,old可以把之前的屏蔽信号集保存起来,如果old为NULL就是不保存。如果保存了old,再次设置信号屏蔽字为old就是取消屏蔽。

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

void fa(int signo){
    printf("捕获了信号%d\n",signo);
}

int main(){
    signal(SIGINT,fa); 
    signal(SIGQUIT,fa);
    printf("pid=%d\n",getpid());
    printf("执行普通代码,不屏蔽信号\n");
    sleep(15);//sleep会被未忽略的信号打断
    printf("执行关键代码,屏蔽信号\n");
    sigset_t set,old;
    sigemptyset(&set);
    sigaddset(&set,2);
    sigaddset(&set,3);
    sigaddset(&set,50);
    sigprocmask(SIG_SETMASK,&set,&old);//屏蔽
    sleep(20);
    printf("关键代码结束,解除屏蔽\n");
    sigset_t pend;
    sigpending(&pend);//取信号屏蔽期间来过的信号
    if(sigismember(&pend,2)){
      printf("信号2来过\n");
    }
    if(sigismember(&pend,3)){
      printf("信号3来过\n");
    }
    sigprocmask(SIG_SETMASK,&old,NULL);
}

六 sigaction()/sigqueue()函数

(常用信号的知识点over)
  sigaction() 可以注册信号的处理方式,功能和signal一样,但sigaction是增强版的signal。

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

void fa(int signo){
  printf("捕获了信号%d\n",signo);
  sleep(5);
}//在信号处理函数的执行期间,会屏蔽相同信号

int main(){
    struct sigaction action = {};
    action.sa_handler = fa;//设置信号处理函数
    //在信号处理函数执行期间,会屏蔽信号3
    sigemptyset(&action.sa_mask);
    sigaddset(&action.sa_mask,3);//屏蔽信号3
    //设置信号第一次是处理函数,然后回复默认处理
    //action.sa_flags = SA_RESETHAND;
    //解除了信号处理函数执行期间对相同信号的屏蔽
    action.sa_flags = SA_NOMASK;
    sigaction(SIGINT,&action,NULL);//注册信号2
    while(1);
}
#include <stdio.h>
#include <signal.h>

void fa(int signo,siginfo_t* info,void* p){
    printf("进程%d发来了信号%d\n",info->si_pid,
        signo);
}//有更多的 信号相关信息

int main(){
    struct sigaction action = {};
    action.sa_flags = SA_SIGINFO;//和fa一致
    action.sa_sigaction = fa;//处理函数用第2个
    sigaction(SIGINT,&action,NULL);
    printf("pid=%d\n",getpid());
    while(1);
}

  sigqueue() 函数可以发送信号,并且在发送信号的同时附加数据。

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

void fa(int signo,siginfo_t* info,void* p){
    printf("进程%d发来了信号%d,附带了值%d\n",
        info->si_pid,signo,info->si_value);
}

int main(){
  struct sigaction action = {};
  action.sa_flags = SA_SIGINFO;
  action.sa_sigaction = fa;
  sigaction(50,&action,NULL);//2 可靠信号
  pid_t pid = fork();
  if(pid == 0){
      int i;
    for(i=0;i<100;i++){
          union sigval v;
          v.sival_int = i;
          sigqueue(getppid(),50,v);  
          }//2
    exit(0);
    }
    while(1);
}

七 计时器

  Linux系统给每个进程维护了3个计时器,真实计时器、虚拟计时器和实用计时器。其中真实计时器最常用。真实计时器是每隔一段时间产生一个SIGALRM信号。
  设置/获取计时器的函数:
  setitimer() getitimer()

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>

void fa(int signo){
  printf("执行了一次\n");
}

int main(){
    signal(SIGALRM,fa);
    struct itimerval timer;
    timer.it_interval.tv_sec = 1;//间隔秒数
    timer.it_interval.tv_usec = 100000;//微秒
    timer.it_value.tv_sec = 3;//开始秒数
    timer.it_value.tv_usec = 0;//微秒  
    setitimer(ITIMER_REAL,&timer,0);
    while(1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值