(三十二)信号——信号处理函数
来源:互联网 发布:java gc 引起 编辑:程序博客网 时间:2024/06/04 23:21
要明白信号处理函数的使用,就要先知道信号的捕捉设定,什么时候会调用信号处理函数和其执行的流程是什么,下图完整的展示了信号捕捉的设定,以及信号处理函数的触发机制:
所以,从上图可以知道,只有当程序中断,异常或系统调用,才会进入内核态,也只有进入了内核态才能处理信号,在这里初学者常常有一个误区,他们会觉得如果我在程序中没有设置中断、不出现异常、不使用系统调用,那就就不会进入内核态,也就不会处理信号了!这是对操作系统错误的理解,由于linux是分时操作系统(但可以改成实时的如:UCOS就是linux修改而来的实时系统,很多人在此有误区),所以当时间片用完时,就会进入内核态,进行进程调度,在此就会处理信号了!
内核给我们提供了一个用于注册用户自定义信号处理函数 的函数sigaction:
#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);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_handler : 早期的捕捉函数sa_sigaction : 新添加的捕捉函数,可以传参 , 和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数sa_mask : 在执行捕捉函数时,设置阻塞其它信号,sa_mask | 进程阻塞信号集,退出捕捉函数后,还原回原有的阻塞信号集 (即用于信号处理函数中是否还处理信号的到达)sa_flags : SA_SIGINFO 或者 0,上面两个函数调用哪一个,0调用sa_handler所指向的函数,1代表sa_sigaction所指向的函数sa_restorer : 保留,已过时
所以我们要做的步骤是:
1)声明sigaction 结构体
2)构造sigaction 结构体
3)用sigaction 函数注册sigaction 结构体
#include <stdio.h>#include <signal.h>/* * #include <signal.h> * int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); * * struct sigaction 定义: * struct sigaction { * void (*sa_handler)(int); * void (*sa_sigaction)(int, siginfo_t *, void *); * int sa_flags; //上面两个函数调用哪一个,0调用最上面那个,1代表调用上面那 * //在信号处理函数中的信号集,信号处理函数运行完之后就恢复原有信号集 * sigset_t sa_mask; * void (*sa_restorer)(void);//现在已经废弃使用了 *}; */void do_sig(int num){ int n = 3; printf("i am do_sig\n"); while(n--) { printf("n = %d", n); sleep(1); } printf("num = %d\n",num);}int main(void){/*****************1.声明sigaction结构体****************/ struct sigaction act; /****************************************************//*****************2.构造sigaction结构体****************/ //标记信号处理函数 //act.sa_handler = SIG_DFL; //默认方式 //act.sa_handler = SIG_IGN; //忽略方式 act.sa_handler = do_sig; //捕捉方式,即指向信号处理函数 //清空临时信号集,当信号处理函数结束时,信号集自动恢复 sigemptyset(&act.sa_mask); //在临时信号集中屏蔽SIGQUIT信号,即在该信号处理函数中不会被SGIQUIT信号中断 sigaddset(&act.sa_mask, SIGQUIT); act.sa_flags = 0;//调用哪一种,在上面的注释中有解释/****************************************************//*****************3.注册sigaction结构体****************/ //注册信号处理函数,当2号SIGINT信号到来时执行用户定义的信号处理函数 sigaction(SIGINT, &act, NULL);/****************************************************/ while(1) { printf("************************\n"); sleep(1); } return 0;}测试方法:运行该程序,按下Ctrl+c发送SIGINT信号,此时会进入用户定义的信号处理函数输出如下:************************************************************************(按下Ctrl+c)i am do_sign = 2n = 1n = 0num = 2************************************************************************************************(按下Ctrl+c)i am do_sign = 2n = 1n = 0num = 2************************************************(按下Ctrl+\退出程序)
在开发过程中,我们往往不希望破坏linux原有的信号处理函数,所以内核也给我们提供了两个专门用于用户自定义的信号(请看这一节中的SIGUSE1和SIGUSE2)10号信号SIGUSE1和12号信号SIGUSE2。
例子:
#include <stdio.h>#include <signal.h>void do_sig(int num){ printf("i am do_sig\n"); printf("num = %d\n",num);}int main(void){ struct sigaction act; act.sa_handler = do_sig; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGQUIT); act.sa_flags = 0; //注册信号处理函数 sigaction(SIGUSR1, &act, NULL); while(1) { printf("************************\n"); sleep(1); } return 0;}测试方法:在一个终端中运行该程序(此时在该终端中会一直输出:********************)在另一终端中输入ps -aux命令查询运行该程序的进程id号并输入kill -10 进程id号 向该程序发送10号消息SIGUSR1此时运行该程序的终端中会输出:i am do_sig num = 10
另一方面,c库函数也为我们提供了一个封装更高层,接口更简单的函数signal:
include <signal.h>typedef void (*sighandler_t)(int)sighandler_t signal(int signum, sighandler_t handler)
例子:
#include <stdio.h>#include <signal.h>void do_sig(int n){ printf("hello\n");}int main(void){ signal(SIGINT, do_sig); while(1) { printf("****************************\n"); sleep(1); } return 0;}运行后按Ctrl+c即可查看效果,若要关闭程序则按Ctrl+\
5 0
- (三十二)信号——信号处理函数
- Linux — 信号 信号处理和信号处理函数详解
- (三十五)信号——SIGCHLD信号处理
- 信号处理—卷积
- 【Get深一度】信号处理(一)——能量信号与功率信号的区别
- (三十)信号——信号产生原因以及信号处理行为的简介
- 信号处理函数
- 信号处理相关函数
- 信号处理函数 signal
- 信号处理函数
- 信号处理相关函数
- 信号处理函数sigaction()
- 信号处理函数
- linux信号处理函数
- Linux信号处理函数
- 信号处理函数
- Linux信号、信号处理和信号处理函数
- Linux信号、信号处理和信号处理函数
- SQL注入漏洞产生的原因 ? 如何防止?
- SpringMVC的初步配置(注解篇)
- 将数据集做成VOC2007格式用于Faster-RCNN训练
- zoj1025
- Linux中如何添加一个新的端口号
- (三十二)信号——信号处理函数
- IT专业技术人员学习网站整理
- 【获利能力分析】相关的设置和事务码
- TENSORFLOW官方文档-MNIST机器学习入门-数据集准备
- UVA 10827 Maximum sum on a torus(子矩阵之和变形)(前缀和)
- 内核链表操作解析
- 微信小程序
- quartz动态添加、更新、删除定时任务
- 关于机器学习的一点看法