|
沙发

楼主 |
发表于 2009-7-5 02:07:10
|
只看该作者
测试代码
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int temp = 0;
struct sigaction act;
/*信号处理函数*/
void handler_sigint(int signo)
{
printf("recv SIGINT\\n");
sleep(5);
temp += 1;
printf("the value of temp is: %d\\n", temp);
sleep(5);
temp = temp + 2 ;
printf("再加一次temp :%d\\n",temp);
printf("in handler_sigint, after sleep\\n");
}
int main()
{
// struct sigaction act;
act.sa_handler = handler_sigint;
act.sa_flags = SA_NOMASK;
/*安装信号处理函数*/
sigaction(SIGINT, &act, NULL);
while(1)
;
return 0;
} 程序执行与输出:beyes@linux-beyes:~/C/base>beyes@linux-beyes:~/C/base> ./sigaction.exe
^Crecv SIGINT
^Crecv SIGINT
the value of temp is: 1
再加一次temp :3
in handler_sigint, after sleep
the value of temp is: 4
再加一次temp :6
in handler_sigint, after sleep
^\\退出 说明:
act 结构体定义在 main() 中或者定义为全局变量都可以。
指定了 SA_NOMASK , 意思就是在处理此信号结束前允许此信号再次递送,相当于中断嵌套。
所以,由以上输出可以看到,在第一次输入 ctrl+c 组合键发送 SIGINT 信号,程序打印输出 recv SIGINT ,表明信号处理程序处理了信号 SIGINT,然后睡眠 5秒。接着,在此睡眠期间,又快速的键入 ctrl+c 组合键一次,由于程序中设定了 sa_flags的值为 SA_NOMASK,因此程序又一次响应 SIGINT信号 ,程序从 sleep()处嵌套调用信号处理函数 handler_sigint,再一次打印出 recv SIGINT ,并睡眠 5秒。
在程序中,
printf("the value of temp is: %d\\n", temp);
sleep(5);
这两条语句的用意是测试一下程序进入中断嵌套后的切换情况。在第一次输出:the value of temp is: 1时,还无法确定程序是在嵌套层还是在首层中。做一下试验,如果我们第二次按下 ctrl+c 是在第一次按下后的2秒进行。那么当在第二次按下组合键时,在发生中断嵌套并输出处理信息程序recv SIGINT 后进入睡眠 5 秒。在嵌套层睡眠期间,首层程序的会存在两种情况:要么醒来,要么根本没有被系统调度而仍然处于挂起状态--也就是 sleep()的时间也不再计时,而是停止了。假设其已经醒来并且系统已经切换到这层去执行,那么 temp值加 1后继续睡眠 5秒。这时,已经轮到嵌套层醒来,temp值会再 +1变成 2后输出。但是,从输出结果来看,输出结果显然和推测的相悖!
所以,可以推断,在嵌套层睡眠时,首层信号处理函数被挂起了,直到嵌套层执行完毕后,再会返回到首层中去,执行信号处理任务完毕后再返回主函数!
这一点,也可以在程序的输出时间间隔中感觉得到。
现在把原程序中的 act.sa_flags = SA_NOMASK 这一行注释掉,再适当修改一下程序,然后重新编译并执行( 执行时,快速按下 ctrl + c 组合键 3 次或 3 次以上)。修改后的程序如下:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int temp = 0;
struct sigaction act;
/*信号处理函数*/
void handler_sigint(int signo)
{
printf("recv SIGINT\\n");
sleep(5);
temp += 1;
printf("the value of temp is: %d\\n", temp);
printf("in handler_sigint, after sleep\\n");
}
int main()
{
// struct sigaction act;
act.sa_handler = handler_sigint;
// act.sa_flags = SA_NOMASK;
/*安装信号处理函数*/
sigaction(SIGINT, &act, NULL);
while(1)
;
return 0;
} 执行时,连续按下 ctrl +c 6 次:beyes@linux-beyes:~/C/base> ./sigaction.exe
^Crecv SIGINT
^C^C^C^C^Cthe value of temp is: 1
in handler_sigint, after sleep
recv SIGINT
the value of temp is: 2
in handler_sigint, after sleep
^\\退出 由输出可见,发送了这么多次的信号,程序只处理了 2 次!
这是因为,在去掉了 SA_NOMASK 后,sigaction() 按照默认的阻塞方式来处理信号。由于 SIGINT 是不可靠信号,不可靠信号不支持排队。对于这种信号的多次发生,它也只会被阻塞一次,即本次信号处理结束后只会再处理一次( 相当于丢失了信号 ),从输出的结果来看,4 个信号确实被丢失掉了。!
|
|