当前位置:   article > 正文

linux的信号捕捉函数详解

linux的信号捕捉函数详解

信号捕捉

signal函数

注册一个信号捕捉函数:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

该函数由ANSI定义,由于历史原因在不同版本的Unix和不同版本的Linux中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction函数。

    void (*signal(int signum, void (*sighandler_t)(int))) (int);

    能看出这个函数代表什么意思吗?  注意多在复杂结构中使用typedef。

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <signal.h>
  6. void do_sig(int a)
  7. {
  8. printf("Hi, SIGINT, how do you do !\n");
  9. }
  10. int main(void)
  11. {
  12. if (signal(SIGINT, do_sig) == SIG_ERR) {
  13. perror("signal");
  14. exit(1);
  15. }
  16. while (1) {
  17. printf("---------------------\n");
  18. sleep(1);
  19. }
  20. return 0;
  21. }


  1. #include <signal.h>
  2. #include <stdio.h>
  3. #include <errno.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. typedef void (*sighandler_t) (int);
  7. void catchsigint(int signo)
  8. {
  9. printf("-----------------catch\n");
  10. }
  11. int main(void)
  12. {
  13. sighandler_t handler;
  14. handler = signal(SIGINT, catchsigint);
  15. if (handler == SIG_ERR) {
  16. perror("signal error");
  17. exit(1);
  18. }
  19. while (1);
  20. return 0;
  21. }


sigaction函数

修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)

    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);  成功:0;失败:-1,设置errno

参数:

act:传入参数,新的处理方式。

oldact:传出参数,旧的处理方式。 【signal.c】

struct sigaction结构体

    struct sigaction {

        void     (*sa_handler)(int);

        void     (*sa_sigaction)(int, siginfo_t *, void *);

        sigset_t   sa_mask;

        int       sa_flags;

        void     (*sa_restorer)(void);

    };

sa_restorer:该元素是过时的,不应该使用,POSIX.1标准将不指定该元素。(弃用)

sa_sigaction:当sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序。(很少使用)  

重点掌握:

① sa_handler:指定信号捕捉后的处理函数名(即注册函数)。也可赋值为SIG_IGN表忽略 或 SIG_DFL表执行默认动作

② sa_mask: 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。

③ sa_flags:通常设置为0,表使用默认属性。

信号捕捉特性

1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。

2. XXX信号捕捉函数执行期间XXX信号自动被屏蔽

3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)

练习1:为某个信号设置捕捉函数 sigaction1.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <signal.h>
  5. /*自定义的信号捕捉函数*/
  6. void sig_int(int signo)
  7. {
  8. printf("catch signal SIGINT\n");//单次打印
  9. sleep(10);
  10. printf("----slept 10 s\n");
  11. }
  12. int main(void)
  13. {
  14. struct sigaction act;
  15. act.sa_handler = sig_int;
  16. act.sa_flags = 0;
  17. sigemptyset(&act.sa_mask); //不屏蔽任何信号
  18. sigaddset(&act.sa_mask, SIGQUIT);
  19. sigaction(SIGINT, &act, NULL);
  20. printf("------------main slept 10\n");
  21. sleep(10);
  22. while(1);//该循环只是为了保证有足够的时间来测试函数特性
  23. return 0;
  24. }


练习2: 验证在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。  【sigaction2.c

  1. /*自动屏蔽本信号,调用完毕后屏蔽自动解除*/
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5. /*自定义的信号捕捉函数*/
  6. void sig_int(int signo)
  7. {
  8. printf("catch signal SIGINT\n");
  9. sleep(10); //模拟信号处理函数执行很长时间
  10. printf("end of handler\n");
  11. }
  12. int main(void)
  13. {
  14. struct sigaction act, old;
  15. act.sa_handler = sig_int;
  16. sigemptyset(&act.sa_mask); //依然不屏蔽任何信号
  17. act.sa_flags = 0;
  18. sigaction(SIGINT, &act, &old); //注册信号处理函数
  19. while(1);
  20. sigaction(SIGINT, &old, NULL); //注册信号处理函数
  21. return 0;
  22. }


练习3:验证sa_mask在捕捉函数执行期间的屏蔽作用。 sigaction3.c

  1. /*当执行SIGINT信号处理函数期间
  2. *多次收到SIGQUIT信号都将被屏蔽(阻塞)
  3. *SIGINT信号处理函数处理完,立刻解除对
  4. *SIGQUIT信号的屏蔽,由于没有捕捉该信号,
  5. *将立刻执行该信号的默认动作,程序退出
  6. */
  7. #include <stdio.h>
  8. #include <signal.h>
  9. #include <unistd.h>
  10. void sig_int(int signo)
  11. {
  12. printf("catch signal SIGINT\n");
  13. sleep(10); //模拟信号处理函数执行很长时间
  14. printf("end of handler\n");
  15. }
  16. int main(void)
  17. {
  18. struct sigaction act;
  19. act.sa_handler = sig_int;
  20. sigemptyset(&act.sa_mask);
  21. sigaddset(&act.sa_mask, SIGQUIT);
  22. /*将SIGQUIT加入信号屏蔽集,这就导致,在调用信号处理函数期间
  23. *不仅不响应SIGINT信号本身,还不响应SIGQUIT*/
  24. act.sa_flags = 0;
  25. sigaction(SIGINT, &act, NULL); //注册信号SIGINT捕捉函数
  26. while(1);
  27. return 0;
  28. }


内核实现信号捕捉过程:


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/913981
推荐阅读
相关标签
  

闽ICP备14008679号