免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3869 | 回复: 11
打印 上一主题 下一主题

[C] APUE2中信号交互处理的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-26 23:17 |只看该作者 |倒序浏览
3可用积分
这是APUE2中程序清单10_6。
APUE2中说当SIGALRM信号中断了其它信号处理程序,则调用longjmp函数会提早终止该信号处理程序。

在本程序中,当程序开始运行后,按下ctrl+c产生SIGINT信号,main捕捉到该信号后调用sig_int处理函数(这个
函数运行的时间超过5s),而程序运行5s后,sleep2函数产生SIGALRM信号,被sig_alrm信号处理程序捕捉到后,该
程序调用longjmp,按照APUE2说的意思,这个SIGALRM信号中断了sig_int信号处理程序(为什么会中断该信号处理
程序呢?SIGALRM信号系统默认动作是终止程序,但是在sleep2中已经捕捉了该信号改变了它的默认处理动作了阿),而它
调用了longjmp函数会终止sig_int信号处理程序,这里我就不明白了,sig_int函数是SIGALRM终止的呢还是longjmp终止的呢?
这里SIGALRM信号被捕捉已经不会终止进程了,而longjmp函数好像也没有终止进程的功能吧?


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <setjmp.h>
  4. #include <signal.h>
  5. #include <unistd.h>

  6. static jmp_buf env_alrm;
  7. static void sig_alrm(int signo);
  8. static void sig_int(int signo);
  9. unsigned int sleep2(unsigned int nsecs);

  10. static void sig_alrm(int signo)
  11. {
  12.         longjmp(env_alrm, 1);
  13. }

  14. unsigned int sleep2(unsigned int nsecs)
  15. {
  16.         if(signal(SIGALRM, sig_alrm) == SIG_ERR){
  17.                 perror("signal error");
  18.                 exit(1);
  19.         }

  20.         if(setjmp(env_alrm) == 0){
  21.                 alarm(nsecs);
  22.                 pause();
  23.         }

  24.         return alarm(0);
  25. }

  26. static void sig_int(int signo)
  27. {
  28.         int                     i, j;
  29.         volatile int            k;

  30.         printf("caught SIGINT!\n");
  31. //      sleep(10);
  32.         for(i = 0; i < 10000000; i++){
  33.                 for(j = 0; j < 10000; j++){
  34.                         k += i * j;
  35.                 }
  36.         }
  37.         printf("after sig_int!\n");
  38. }

  39. int main(int argc, char** argv)
  40. {
  41.         unsigned int            unslept;

  42.         if(signal(SIGINT, sig_int) == SIG_ERR){
  43.                 perror("signal error");
  44.                 exit(2);
  45.         }

  46.         unslept = sleep2(5);
  47.         printf("sleep2 returned : %d\n", unslept);

  48.         exit(0);
  49. }
复制代码

[ 本帖最后由 xiaozhu2007 于 2007-12-27 00:22 编辑 ]

最佳答案

查看完整内容

我试着给你解释一下。sig_int函数应该是longjmp终止的。因为当调用longjmp时,它跳转到slee2函数中,这样它把sig_int的栈帧给跳了过去,sig_int函数就莫名的结束的。你做一下习题10.3,如果对栈帧不太了解,参考setjmp和longjmp那一节。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2007-12-26 23:17 |只看该作者
我试着给你解释一下。
sig_int函数应该是longjmp终止的。
因为当调用longjmp时,它跳转到slee2函数中,
这样它把sig_int的栈帧给跳了过去,sig_int函数
就莫名的结束的。你做一下习题10.3,
如果对栈帧不太了解,参考setjmp和longjmp那一节。

论坛徽章:
0
3 [报告]
发表于 2007-12-26 23:55 |只看该作者
汗,你主程序那里应该调用 sleep2 吧? 怎么调用的是 sleep? 这样一来 setjmp 没有运行,alrm 也没有设置。

论坛徽章:
0
4 [报告]
发表于 2007-12-27 00:23 |只看该作者

回复 #2 主旋律 的帖子

不好意思大意了,改过来了,不过问题还是不明白!

论坛徽章:
0
5 [报告]
发表于 2007-12-27 15:34 |只看该作者
原帖由 xiaozhu2007 于 2007-12-26 23:17 发表
这是APUE2中程序清单10_6。
APUE2中说当SIGALRM信号中断了其它信号处理程序,则调用longjmp函数会提早终止该信号处理程序。

在本程序中,当程序开始运行后,按下ctrl+c产生SIGINT信号,main捕捉到该信号后调 ...

如lenovo所说,它是被longjmp中断的。
linux中,当一个信号在执行它的hanlder的时候,只会阻塞同类型的信号,例如这里在处理SIGINT,该信号就被阻塞至处理结束。但其它信号还是会打断当前信号的处理的。除非你自己将它屏蔽掉了。
所以这里在sig_int中执行的时候,SIGALRM信号到来,由于先前已设置了它的处理函数,会转入sig_alrm执行。sig_alrm执行了longjmp,跳转到setjmp之后继续执行,也就是SIGALRM信号处理完成,返回。程序继续运行直到结束。所以你应该可以看到 printf("sleep2 returned : %d\n", unslept);的输出。程序是正常执行结束的,被中断的只是SIGINT的处理

论坛徽章:
0
6 [报告]
发表于 2007-12-27 22:30 |只看该作者
明白了。
没有执行到longjmp的时候栈空间是这样的:
(栈的底部,高地址)
   main的栈帧
   sleep2的栈帧
   sig_int的栈帧
   sig_alrm的栈帧

当sig_alrm调用longjmp函数的时候,程序跳转到调用setjmp的地方即main栈帧继续执行,
此时栈空间是这样的:
(栈的底部,高地址)
   main的栈帧
   sleep2的栈帧

所以sig_int函数是被longjmp终止的。
我思考这个问题的时候咋就没想到longjmp会跳跃珍帧的问题呢?笨啊!

论坛徽章:
0
7 [报告]
发表于 2007-12-27 22:55 |只看该作者
如lenovo所说,它是被longjmp中断的。
linux中,当一个信号在执行它的hanlder的时候,只会阻塞同类型的信号,例如这里在处理SIGINT,该信号就被阻塞至处理结束。但其它信号还是会打断当前信号的处理的。除非你自己将它屏蔽掉了。

1。其中“但其它信号还是会打断当前信号的处理的。除非你自己将它屏蔽掉了。”是不是应该加上“或者设置了该信号的处理程序”
因为执行下面的程序,一开始按下ctrl+c,程序执行sig_int,当5s后SIGALRM信号被处理程序sig_alrm捕捉的时候,并不打断当前sig_int处理程序。
2。还有,linux的sleep函数是不是使用alarm函数实现的,所以,在同一个程序中,最好不要同时使用sleep和alarm函数,否则会出现alarm函数的设置覆盖,
比如本例子sig_int中的程序段:
        for(i = 0; i < 10000000; i++){
                for(j = 0; j < 10000; j++){
                        k += i * j;
                }
        }
就不可以使用sleep函数代替,因为main中有alarm,否则程序不会出现正确的结果。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>

  4. void sig_int(int signo);
  5. void sig_alrm(int signo);

  6. int main(int argc, char** argv)
  7. {
  8.         if(signal(SIGINT, sig_int) == SIG_ERR){
  9.                 perror("signal error");
  10.                 exit(1);
  11.         }
  12.         if(signal(SIGALRM, sig_alrm) == SIG_ERR){
  13.                 perror("signal error");
  14.                 exit(2);
  15.         }
  16.         alarm(5);
  17.         pause();

  18.         exit(0);
  19. }

  20. void sig_int(int signo)
  21. {
  22.         int                     i, j;
  23.         volatile int            k;

  24.         printf("begin sig_int\n");

  25.         for(i = 0; i < 10000000; i++){
  26.                 for(j = 0; j < 10000; j++){
  27.                         k += i * j;
  28.                 }
  29.         }

  30.         printf("end sig_int\n");
  31. }

  32. void sig_alrm(int signo)
  33. {
  34.         printf("caught SIGALRM\n");
  35. }
复制代码

论坛徽章:
0
8 [报告]
发表于 2007-12-28 13:06 |只看该作者

回复 #7 xiaozhu2007 的帖子

>>1。其中“但其它信号还是会打断当前信号的处理的。除非你自己将它屏蔽掉了。”是不是应该加>>上“或者设置了该信号的处理程序”
>>因为执行下面的程序,一开始按下ctrl+c,程序执行sig_int,当5s后SIGALRM信号被处理程序s>>ig_alrm捕捉的时候,并不打断当前sig_int处理程序。
不,sig_int会被打断。新的信号(非同一个信号)会打断当前信号处理程序的执行。所以你应该看不到printf("after sig_int!\n");这句的输出

论坛徽章:
0
9 [报告]
发表于 2007-12-28 13:45 |只看该作者
原帖由 xiaozhu2007 于 2007-12-27 22:55 发表

1。其中“但其它信号还是会打断当前信号的处理的。除非你自己将它屏蔽掉了。”是不是应该加上“或者设置了该信号的处理程序”
因为执行下面的程序,一开始按下ctrl+c,程序执行sig_int,当5s后SIGALRM信号被 ...


当然打断啊,只是执行完ALARM的信号处理函数后就返回刚才的上下文了.

论坛徽章:
0
10 [报告]
发表于 2007-12-28 15:41 |只看该作者
不对吧,我说的是下面的程序啊!当产生了SIGALRM信号的时候,并没有中断sig_int程序哦!!!

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>

  4. void sig_int(int signo);
  5. void sig_alrm(int signo);

  6. int main(int argc, char** argv)
  7. {
  8.         if(signal(SIGINT, sig_int) == SIG_ERR){
  9.                 perror("signal error");
  10.                 exit(1);
  11.         }
  12.         if(signal(SIGALRM, sig_alrm) == SIG_ERR){
  13.                 perror("signal error");
  14.                 exit(2);
  15.         }
  16.         alarm(5);
  17.         pause();

  18.         exit(0);
  19. }

  20. void sig_int(int signo)
  21. {
  22.         int                     i, j;
  23.         volatile int            k;

  24.         printf("begin sig_int\n");

  25.         for(i = 0; i < 10000000; i++){
  26.                 for(j = 0; j < 10000; j++){
  27.                         k += i * j;
  28.                 }
  29.         }

  30.         printf("end sig_int\n");
  31. }

  32. void sig_alrm(int signo)
  33. {
  34.         printf("caught SIGALRM\n");

复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP