Linux编程复习(3)——信号与中断

信号是响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。某些状况就是指某些条件错误,如内存段冲突、浮点处理器错误或者非法指令等。信号是在软件层次上对中断的一种模拟,所以信号也称为是软中断
信号与中断的相似点:
1,都采用相同的额异步通信方式
2,当检测出有信号或中断请求时,都暂停证在执行的程序而转去执行相应的处理程序
3,都在处理完毕之后返回到原来的断点
4,对信号或中断都可进行屏蔽

信号与中断的区别:
1,中断有优先级,而信号没有,所有的信号都是平等的
2,信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行的
3,中断响应是及时的,而信号响应通常都有较大的事件延迟

进程对信号的三种响应:
1,忽略信号,除了SIGKILL,SIGSTOP
2,捕获并处理信号,内核中断正在执行的代码,转去执行先前注册处
3,执行默认操作,默认操作通常是终止进程,取决于被发送的信号


中断一个中断处理程序到系统中__sighandler_t signal(iny signum, __sighandler_t handler);signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由signum给出,接收到指定信号时将要调用的函数由handler给出;
handler这个函数必须有一个int类型的参数,即接收到的信号代码,当然handler也可以是SIG_IGN(屏蔽该信号)、SIG_DFL(恢复默认行为)这两个特殊值

超简单例子
SIGINT对应键盘ctrl+c发出的信号

    #include
  2 #include<sys/stat.h>
  3 #include<sys/wait.h>
  4 #include<sys/types.h>
  5 #include<fcntl.h>
  6 
  7 #include<stdlib.h>
  8 #include<stdio.h>
  9 #include<errno.h>
 10 #include<string.h>
 11 #include<signal.h>
 12 
 13 #define ERR_EXIT(m) \
 14     do \
 15     { \
 16         perror(m); \
 17         exit(EXIT_FAILURE); \
 18     }while(0)
 19 
 20 void handler(int sig);
 21 
 22 int main(int argc, char *argv[])
 23 {
 24     signal(SIGINT, handler);//注册一个ctrlc的信号,如果捕捉到了这个信号,就去执行handler函数
 25     for(;;);
 26     return 0;
 27 }
 28 void handler(int sig)
 29 {
 30     printf("recv a sig = %d\n",sig);
 31 }

结果
Linux编程复习(3)——信号与中断_第1张图片


信号在内核中的表示、信号阻塞与未决、信号集操作函数、sigprocmask(用来获取或改变进程中的信号屏蔽字)

1,执行信号的处理动作称为信号递达,信号产生到递达之间的状态称为信号未决,进程可以选择阻塞某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

信号集操作函数:
#include

int sigemptyset(sigset_t* set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t * set, int_signo);
int sigdelset(sigset_t* set, int signo);
int sigismember(const sigset_t *set, int signo);

获取/改变 进程中的信号屏蔽字:int sigprocmask(int how, const sigset_t *set, sigset_t *oset)第三个参数是改变之前的信号屏蔽字的状态,第一个参数改变方式有三种SIG_BLOCKSIG_UNBLOCKSIG_SETMASK

sigpending(&set)函数可以获取进程中的未决信号集合保存到set中

例子信号从产生到递达的一个过程
bset将SIG_INIT进行阻塞,但接收到SIG_QUIT即ctrl/时取消阻塞,始终用函数将未决信号集打印出来
设置阻塞或者取消阻塞都是要用自定义的一个set来进行sigprocmask来设置的

 16 void printsigset(sigset_t *set)//打印未决信号集内容
 17 {
 18         int i;
 19         for(i=1; i<NSIG; i++)
 20         {
 21                 if(sigismember(set, i))
 22                         putchar('1');
 23                 else
 24                         putchar('0');
 25         }
 26         printf("\n");
 27 }
 28 void handler(int sig);
 29 int main(int argc, char*argv[])
 30 {
 31         sigset_t pset;
 32         sigset_t bset;sigemptyset(&bset);sigaddset(&bset, SIGINT);
 33         if(signal(SIGINT, handler) == SIG_ERR)
 34                 ERR_EXIT("signal error");
 35         if(signal(SIGQUIT, handler) == SIG_ERR)//if ctrl/, unblock
 36                 ERR_EXIT("signal error");
 37         sigprocmask(SIG_BLOCK, &bset, NULL);//use bset
 38         for(;;)
 39         {
 40             sigpending(&pset);
 41             printsigset(&pset);
 42             sleep(1);
 43         }
 44 
 45 
 46         return 0;
 47 }
 48 
 49 void handler(int sig)
 50 {
 51         if(sig == SIGINT)
 52                 printf("recv a sig = %d\n", sig);
 53         else if(sig == SIGQUIT)
 54         {
 55                 sigset_t uset;
 56                 sigemptyset(&uset);
 57                 sigaddset(&uset, SIGINT);
 58                 sigprocmask(SIG_UNBLOCK, &uset, NULL);
 59         }
 60 }

sigaction函数

int sigaction(int signum, const struct sigaction *act, const struct sigaction *old)
第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些信号等

struct sigaction{
	void (*sa_handler)(int);//1
	void (*sa_sigaction)(int, siginfo_t*, void*);//2,只能选一个,一般就选1
	sigset_t sa_mask;//指定信号屏蔽字
	int sa_flags;//改变信号的一些行为
	void(*sa_restorer)(void);//废弃
}

handler包含在sigaction这个结构体中

    void handler(int sig);
 29 int main(int argc, char*argv[])
 30 {
 31         struct sigaction act;
 32         act.sa_handler = handler;
 33         sigemptyset(&act.sa_mask);
 34         act.sa_flags = 0;
 35  
 36         if(sigaction(SIGINT, &act, NULL)<0)
 37                 ERR_EXIT("sigaction error\n");
 38         for(;;)
 39                 pause();
 40         return 0;
 41 }
 42 void handler(int sig)
 43 {
 44     printf("recv a sig = %d\n", sig);
 45 }

关于sa_mask,指定信号掩码,在一个信号执行过程中,sa_mask中的信号发生了也不会递达,会被阻塞直到真正该执行的信号函数结束
在sa_mask中加入SIGQUIT信号,那么在SIGINT捕捉到执行handler的过程中,发生sa_mask中的信号也会被屏蔽

 int main(int argc, char*argv[])
 30 {
 31         struct sigaction act;
 32         act.sa_handler = handler;
 33         sigemptyset(&act.sa_mask);
 34         sigaddset(&act.sa_mask, SIGQUIT);//
 35         act.sa_flags = 0;
 36 
 37         if(sigaction(SIGINT, &act, NULL)<0)
 38                 ERR_EXIT("sigaction error\n");
 39         for(;;)
 40                 pause();
 41         return 0;
 42 }
 43 void handler(int sig)
 44 {
 45     printf("recv a sig = %d\n", sig);
 46     sleep(5);
 47 }

sa_flags的用法有需要再补吧233


时间与定时器相关的操作

  • 三种不同精度的睡眠
  • setitimer
  • getitimer

三种不同精度的睡眠
1,unisigned int sleep(uninsigned int seconds);,返回剩余秒数while(n = sleep(n))
2,int usleep(useconds_t usec);微秒
3,int nanosleep(const struct timepec *req, struct timespec *rem);纳秒,第二个参数时剩余睡眠时间
三种不同精度就对应三种时间结构

getitimer()/setitimer()功能描述:
获取或设定间歇计时器的值。系统为进程提供三种类型的计时器,每一类以不同的时间域递减其值。当计时器超时,信号被发送到进程,之后计时器重启动。

用法:

#include 

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);

参数:
which:间歇计时器类型,有三种选择

ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。
ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。
ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。

你可能感兴趣的:(linux,linux)