sigjmp longjmp 和 sigsetjmp siglongjmp比较

本文通过三个实验探讨了在Unix环境中使用sigjmp longjmp与sigsetjmp siglongjmp进行信号处理的区别。详细展示了不同情况下信号屏蔽字的变化,揭示了信号处理程序正常结束及异常退出时信号屏蔽字的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读《Unix环境高级编程》P283页  10.15处的体会。(错误之处,望大家批评指正)

本文通过几个实验说明sigjmp  longjmp 和 sigsetjmp  siglongjmp的区别。

实验一:执行信号X(任意信号)处理程序时,X信号会被自动加入到信号屏蔽字。信号处理程序执行完毕,信号屏蔽字会恢复原来的。

    1 #include <stdio.h>                                                                                                                              
    2 #include "apue.h"
    3 #include <signal.h>
    4 #include <setjmp.h>
    5 
    6 
    7 void deal_sig(int a)
    8 {
    9     sigset_t sigpend;
   10     sigset_t sigmask;
   11     sleep(5);//延时等待SIGQUIT再次发生
   12     sigpending(&sigpend);
   13     sigprocmask(0,NULL,&sigmask);
   14 
   15     if(sigismember(&sigpend,SIGQUIT))
   16     {
   17         printf("SIGQUIT is pending\n");
   18     }
   19     else
   20     {
   21         printf("SIGQUIT is not pending\n");
   22     }
   23 
   24     if(sigismember(&sigmask,SIGQUIT))
   25     {
   26         printf("SIGQUIT is in sigmask\n");
   27     }
   28     else
   29     {
   30         printf("SIGQUIT is not in sigmask\n");
   31     }
   32 
   33 }
   34 
   35 int main()
   36 {
   37     int sleep_ret;
   38     sigset_t sigmask;
   39     if(signal(SIGQUIT,deal_sig)==SIG_ERR)
   40     {
   41         printf("signal error\n");
   42         exit(1);
   43     }
   44     sleep_ret = sleep(5);//延时等待信号发生
   45 
   46 
   47     sigprocmask(0,NULL,&sigmask);
   48     if(sigismember(&sigmask,SIGQUIT))
   49     {
   50         printf("main : SIGQUIT is in sigmask\n");
   51     }
   52     else
   53     {
   54         printf("main : SIGQUIT is not in sigmask\n");
   55     }
   56 
   57     printf("sleep_ret = %d\n",sleep_ret);
   58     exit(0);
   59 }

运行结果

^\^\SIGQUIT is pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
sleep_ret = 4

第一SIGQUIT信号发生时,正在执行信号处理程序,此时再次发生该信号,信号处于未决态,信号被自动加入信号屏蔽字。

信号处理程序执行完,第二次的信号开始处理,信号又被加入信号屏蔽字,但是没有第三次发生SIGQUIT,因此没有SIGQUIT在未决态。

main:是主函数打印的,信号处理程序返回,检查信号屏蔽字,发现,SIGQUIT不在信号屏蔽字。(证明信号处理程序返回,自动恢复了信号屏蔽字。)

信号处理程序返回,sleep不会继续睡眠,直接返回剩余的时间,因此sleep_ret=4。

实验二:如果用longjmp跳出信号处理程序,进程的信号屏蔽字会发生什么。不同平台处理方式不同。

Linux3.2.0和Solaris不会恢复信号屏蔽字,FreeBSD8.0,MacOS X 10.6.8会保存和恢复信号屏蔽字。

测试环境Ubantu

    1 #include <stdio.h>                                                                                                                              
    2 #include "apue.h"
    3 #include <signal.h>
    4 #include <setjmp.h>
    5 
    6 static jmp_buf jmpbuf;
    7 
    8 void deal_sig(int a)
    9 {
   10     sigset_t sigpend;
   11     sigset_t sigmask;
   12     sleep(5);
   13     sigpending(&sigpend);
   14     sigprocmask(0,NULL,&sigmask);
   15      
   16     if(sigismember(&sigpend,SIGQUIT))
   17     {
   18         printf("SIGQUIT is pending\n");
   19     }
   20     else
   21     {
   22         printf("SIGQUIT is not pending\n");
   23     }
   24 
   25     if(sigismember(&sigmask,SIGQUIT))
   26     {
   27         printf("SIGQUIT is in sigmask\n");
   28     }
   29     else
   30     {
   31         printf("SIGQUIT is not in sigmask\n");
   32     }
   33     longjmp(jmpbuf,1);
   34 }
   35 
   36 int main()
   37 {
   38     sigset_t sigmask;
   39     sigset_t sigpend;
   40     if(signal(SIGQUIT,deal_sig)==SIG_ERR)
   41     {
   42         printf("signal error\n");
   43         exit(1);
   44     }
   45     while(setjmp(jmpbuf)==0);
   46 
   47     sigprocmask(0,NULL,&sigmask);
   48     if(sigismember(&sigmask,SIGQUIT))
   49     {
   50         printf("main : SIGQUIT is in sigmask\n");
   51     }
   52     else
   53     {
   54         printf("main : SIGQUIT is not in sigmask\n");
   55     }
   56     sigpending(&sigpend);
   57     if(sigismember(&sigpend,SIGQUIT))
   58     {
   59         printf("main : SIGQUIT is pending\n");
   60     }
   61     else
   62     {
   63         printf("main : SIGQUIT is not pending\n");
   64     }
   65 
   66     exit(0);
   67 }

运行结果

^\^\SIGQUIT is pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : SIGQUIT is pending

第一次发生信号,进入信号处理程序,SIGQUIT自动加入信号屏蔽字,第二次发生的信号处于未决态。

信号处理程序返回,SIGQUIT还在屏蔽字中,第二次发生的信号还是未决态。

实验三:实验二的sigjmp  longjmp 换成 sigsetjmp  siglongjmp

    1 #include <stdio.h>
    2 #include "apue.h"                                                                                                                               
    3 #include <signal.h>
    4 #include <setjmp.h>
    5 
    6 static jmp_buf jmpbuf;
    7 
    8 void deal_sig(int a)
    9 {
   10     sigset_t sigpend;
   11     sigset_t sigmask;
   12     sleep(5);
   13     sigpending(&sigpend);
   14     sigprocmask(0,NULL,&sigmask);
   15 
   16     if(sigismember(&sigpend,SIGQUIT))
   17     {
   18         printf("SIGQUIT is pending\n");
   19     }
   20     else
   21     {
   22         printf("SIGQUIT is not pending\n");
   23     }
   24 
   25     if(sigismember(&sigmask,SIGQUIT))
   26     {
   27         printf("SIGQUIT is in sigmask\n");
   28     }
   29     else
   30     {
   31         printf("SIGQUIT is not in sigmask\n");
   32     }
   33     siglongjmp(jmpbuf,1);
   34 }
   35 
   36 int main()
   37 {
   38     sigset_t sigmask;
   39     sigset_t sigpend;
   40     if(signal(SIGQUIT,deal_sig)==SIG_ERR)
   41     {
   42         printf("signal error\n");
   43         exit(1);
   44     }
   45     while(sigsetjmp(jmpbuf,1)==0);
   46 
   47     sigprocmask(0,NULL,&sigmask);
   48     if(sigismember(&sigmask,SIGQUIT))
   49     {
   50         printf("main : SIGQUIT is in sigmask\n");
   51     }
   52     else
   53     {
   54         printf("main : SIGQUIT is not in sigmask\n");
   55     }
   56     sigpending(&sigpend);
   57     if(sigismember(&sigpend,SIGQUIT))
   58     {
   59         printf("main : SIGQUIT is pending\n");
   60     }
   61     else
   62     {
   63         printf("main : SIGQUIT is not pending\n");
   64     }
   65 
   66     exit(0);
   67 }

运行结果1:sigsetjmp(jmpbuf,1)自动恢复了信号屏蔽字。

^\^\SIGQUIT is pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
main : SIGQUIT is not pending

运行结果2:sigsetjmp(jmpbuf,0)第二个参数填0,没有自动恢复信号屏蔽字。(非零会恢复)

^\^\SIGQUIT is pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : SIGQUIT is pending

总结:sigjmp  longjmp 和 sigsetjmp  siglongjmp比较

1、信号处理程序正常结束,会恢复原来的信号屏蔽字。

2、在Linux3.2.0中,longjmp跳出信号处理程序,不会恢复原来的信号屏蔽字。

3、siglongjmp的第二个参数非零,恢复信号屏蔽字,为0则不恢复。

在C++中,如果你想在程序运行过程中打断`while(1)`这样的无限循环,通常需要一种中断机制,如操作系统提供的信号处理或者是自定义的条件变量。这里提供两种常见的解决方案: 1. **信号处理**: - 使用`sigsetjmp``longjmp`函数,结合`signal`函数可以实现异常退出。你可以注册一个信号处理器,当接收到特定信号(如SIGINT)时,通过`longjmp`跳出循环。例如: ```cpp #include <curses.h> sigjmp_buf env; void signal_handler(int signum) { if (setjmp(env)) { // 用户中断,跳出循环 break; } // 其他循环逻辑... } int main() { signal(SIGINT, signal_handler); while (true) { // 循环体... jmp_buf(env); // 用于设置跳转环境 } } ``` 2. **使用条件变量**: 如果你是在控制台上编写程序,可以利用`boost::asio`库或者其他线程库中的条件变量配合互斥锁,创建一个退出通道。例如: ```cpp #include <thread> #include <mutex> std::mutex m; std::condition_variable cv; bool stop = false; void infinite_loop() { while (!stop) { // 循环逻辑... cv.wait(m, [] { return stop; }); } } int main() { std::thread t(infinite_loop); // 等待用户输入或某个事件,然后设置stop std::cout << "Press Ctrl+C to exit.\n"; std::cin.get(); stop = true; cv.notify_one(); // 唤醒等待的线程 t.join(); // 等待线程结束 } ``` 无论哪种方法,都要注意避免直接修改循环条件,因为这可能会导致程序状态混乱。在设计时应保证安全性健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值