linux系统编程之信号(一)

今天起,开始新的知识的学习,对于上个系列进程的学习还差一个理论上的总结,这个会下次补回来,以便通过实践之后,再用理论将其巩固一下,好了,话不多说,开始进入这个主题的学习----信号,很重要,但不是太容易理解,所以得一步一步来!

中断【纯概念,但是很重要】: 在学习信号之前,首先需要理解一下什么是中断,因为信号与中断有很多的相似之处,中断,顾名思义就是中途打断: 那什么是 异步事件呢? 它是没有一定时序关系,随机发生的事件,在中断技术出现之前,计算机对异步事件处理能力是有限的,通过是通过查询的方式来处理的,举一个现实生活中的例子: 比如张三正在看书,这时厨房里又正在烧开水,这时,张三看书时并不知道水是否烧开了,他就需要跑到厨房当中"查询"一下水是否烧开了,然后再回来看书,这时又不放心厨房水是否烧开了,于是又跑进厨房查询,如此循环,直到水烧开之后,他才能够静下心来看自己的书,这就是典型的 查询技术。 有了中断技术后,又是如何的呢?还是以上面这个例子: 张三在看书的同时,设置一个闹钟,比如说是10分钟的闹钟,当水烧开的时候,会响铃,其中响铃可以看作是一个 中断信号,闹钟可以看成是一个 中断源,当闹钟响之后,张三就会去处理这一次的中断事件,也就是跑到厨房将煤气给关闭,将开水倒进热水瓶当中,这叫 中断执行程序,实际上张三在做这件事之前,需要 保护现场,记住当前看到了第几页,当执行完中断执行程序之后,则 恢复现场,继续从之前看到的页数开始看书,这就是中断执行的整个流程,总结一下: 中断源  ->  中断屏蔽  ->  保护现场  ->  中断处理程序  ->  恢复现场 那 中断处理程序是保存在哪的呢?实际上,它的入口地址是保存在 中断向量表当中的,由于 计算机中的中断个数是固定的,一般在操作系统启动的时候,会初始化一个中断向量表,它会保存固定个数的中断处理程序入口的地址,这样的话,CPU就可以根据中断号,从中断向量表当中找到对应中断的中断处理程序的入口地址,从而调用处理程序。 对于闹钟这个中断源,产生了一个中断信号, 不同的中断源会产生不同的中断信号,再回到这个例子,张三在看书的时候,可能闹钟响的同时,会听到外面有人敲门的中断信号到来,还有可能是电话响起来产生另外一个中断信号,但是对于同时到来的中断,张三可以决定哪个中断先处理,这也就是中断的优先级,他觉得开水烧开的中断优化级最高。另外张三也有可能屏蔽一些不必要的中断,比如说电话响铃了,在看书之时,他觉得这个中断是可以屏蔽的,也就是 中断屏蔽. 中断分类: 比如键盘产生的中断、鼠标产生的中断、打印机产生的中断等,这些都是属于硬件中断。 比如说除0中断、单步执行、对于X86平台来说执行了一个INT指令,从用户空间到内核空间 信号【核心】:   信号与中断总结: 信号名称: 那在linux/unix下,到底有哪些信号呢?我们可以通过一个命令进行查看: 这些信号都有它们不同的涵义: 对于这些信号的 默认处理行为(也就是我们可以自定义自己的行为),可以在man手册上查询到: 进程对信号的三种响应: 当对于到来的信号,可以有三种不同的响应 为什么呢?SIGKILL是杀死进程的信号,它是9号进程: 在shell命令中,我们可以用kill -9 pid来对一个进程进行杀死,如果进程能够忽略9号信号的话,意味着当管理员向进程发送9号信号时,如果进程可以屏蔽不处理的话,那就无法杀死一个非法的进程了,而同理,SIGSTOP是停止一个进程信号, 也就是我们看到的信号对应的action,上面有介绍过: signal: 下面来学一下安装信号函数: 下面以代码来进行说明: 编译运行: 按下ctrl+c: 可以信号是一种异步事件的响应,当响应完之后,会还原现场,又回到了for死循环代码上了: 这时按下ctrl+\退出: 实际上,ctrl+\会产生一个退出信号: 由于我们程序没有注册该信号,所以由系统默认处理,既程序结束。 对于signal函数,它的返回值为它注册的上一个信号的处理程序,这样说有点空洞,下面以程序来说明一下:
#include 
#include 
#include 
#include 
#include #include 
#include 
#include 
#include 
#include #define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)void handler(int sig);
int main(int argc, char *argv[])
{__sighandler_t oldhandler;oldhandler = signal(SIGINT, handler);//这时返回的处理程序是注册handler之前的,也就是系统默认的处理程序if (oldhandler == SIG_ERR)ERR_EXIT("signal error");while (getchar() != '\n')//死循环是为了测试,当按了ctrl+c之后,会不断死循环,直到按了回车键;if (signal(SIGINT, oldhandler) == SIG_ERR)//这时,再次注册信号,但是这次是注册成了默认处理程序,而ctrl+c的默认处理就是终止程序ERR_EXIT("signal error");for (;;) ;return 0;
}void handler(int sig)
{printf("recv a sig=%d\n", sig);
}

编译运行:

按回车键:

这时,再按ctrl+c:

实际上,恢复默认的处理行为,还可以用它来代替:

编译运行,输出效果一样:

好了,今天的学习先到这,下回见!


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部