为了增强程序的稳定性,在信号处理函数中应使用可重入函数。
可重入函数:指的是一个可以被多个任务调度的过程,任务在调度中不必担心数据是否出错。因为进程在收到信号后,就将跳转到信号处理程序去执行。如果信号处理程序中使用了不可重入函数,那么信号处理函数可能会修改原进程中不应被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料后果。不可重入函数在信号处理程序中被视为不安全函数。
可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。
man 7 signal查看可重入。
满足下列条件的函数多数是不可再入的:
1、使用静态数据结构或者全局变量,如getlogin(),gmtime(),getgrgid(),getgrnam()等;
2、函数实现时,调用了malloc()或者free()函数等;
3、实现时使用了标准IO函数。
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<string.h> 9 10 #include<signal.h> 11 #define ERR_EXIT(m) 12 do 13 { 14 perror(m); 15 exit(EXIT_FAILURE); 16 }while(0) //宏要求一条语句 17 typedef struct{ 18 int a; 19 int b; 20 }TEST; 21 TEST g_data; 22 void handler(int sig); 23 int main(int argc,char*argv[]) 24 { 25 26 TEST zeros={0,0}; 27 TEST ones={1,1}; 28 if(signal(SIGALRM,handler)==SIG_ERR) 29 ERR_EXIT("signal error"); 30 g_data=zeros; 31 alarm(1);//过一秒发送一个SIGALRM信号 32 for(;;) 33 { 34 g_data=zeros; 35 g_data=ones; 36 } 37 return 0; 38 }
//正常想法:要么输出 0 0 ;要么输出 1 1.m 39 void unsafe_fun()//导致不可重入原因:访问全局变量(程序与信号处理函数共享) 40 { 41 printf("%d %d ",g_data.a,g_data.b);//输出结果可能为0 1或 1 0 可能在for循环中g_data.a=zeros.a g_data.b=zeros.b之间1秒到了,不是原子操作 42 } 43 void handler(int sig)//sig是signum 44 { 45 unsafe_fun(); 46 alarm(1);//每隔一秒发送一次。,间接递归 han-alrm-han 47 }