信号的可重入性讨论
对于进程调用“慢”的系统调用时,如果发生了信号中断,内核会终止系统调用,重新执行。
对于用户函数中静态存储区(或全局数据区)的变量接受到信号的中断处理后可导致函数不可重入。正常流程和中断处理流程会对变量的数值相互覆盖影响。
对第一点先不作讨论,后续有时间再补充,这里主要通过一个代码示例来讨论第二种情况。下面是代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
int g_a[10];
void out(int n)
{
int s_a[10];
int i = 0;
for(i;i < 10;i++)
{
g_a[i] = n;
s_a[i] = n;
sleep(1);
}
printf("\n...............g data............\n");
for(i = 0;i < 10;i++)
printf("%d ",g_a[i]);
printf("\n...............s data............\n");
for(i = 0;i < 10;i++)
printf("%d ",s_a[i]);
}
void sig_handler(int signo)
{
printf("\n........catch SIGTSTP.........\n");
out(20);
printf("\n........end signal...........\n");
}
int main(void)
{
if(signal(SIGTSTP,sig_handler) == SIG_ERR)
{
fprintf(stderr,"signal : %s\n",strerror(errno));
exit(1);
}
out(10);
printf("\n");
return 0;
}
要想了解上述代码的运行过程,最好的办法是用IDE进行单步调试。这里我用的Qt Creator.(不得不说,linux找个好用的IDE不容易啊)
下面解释一下代码的运行的流程
- 首先,为SIGTSTP信号注册一个处理函数,即sig_handler
- 接着调用out(10),注意,这里传入的参数是10,为了给发送信号争取时间,在out里面的for循环里,每赋值一次,进行sleep(1)
- ok,假设大概执行了3秒的样子,假设此时out(10)里面的i的值为2,也就是执行了s_a[0]=10,s_a[1]=10,s_a[2]=10,g_a[0]=10,g_a[1]=10,g_a[2]=10.我觉得我需要画一张图
- 然后这时候按下Ctrl+Z发送一个SIGTSTP信号,然后程序转去执行sig_handler函数里的内容,原来执行的地方被保存起来。在sig_handler函数里,我们打印了两行输出内容,然后是out(20),也就是进入了out函数,此时函数里重新建立了一个s_a[10],但是由于g_a[10]是全局变量,所以操作的还是原来的g_a[10].记住,重点是一个新的s_a[10]和原来的g_a[10] (对应开始的全局数据区),这里我觉得还需要一张图,假定为out(20)执行完毕后的状态,这里的输出结果是应该是`…………….catch SIGTSTP………..
…………….g data…………..
20 20 20 20 20 20 20 20 20 20
…………….s data…………..
20 20 20 20 20 20 20 20 20 20
…………….end signal…………..
…………….g data…………..
5. 当sig_handler函数执行完毕后,我们返回刚才接收信号之前的状态,此时讲要执行的是for循环的第四次循环,也就是i=3的情况,上图![state03](https://img-blog.csdn.net/20160813215754283),然后执行完原来的out(10),打印出结果
20 20 20 10 10 10 10 10 10 10
…………….s data…………..
10 10 10 10 10 10 10 10 10 10 `
6.所以最后的输出结果也就是这样的