zoukankan      html  css  js  c++  java
  • 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 <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #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() != '
    ')//死循环是为了测试,当按了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
    ", sig);
    }

    编译运行:

    按回车键:

    这时,再按ctrl+c:

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

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

    好了,今天的学习先到这,下回见!
  • 相关阅读:
    nginx uwsgi django
    ubuntu config proxy
    jdbc调用sparksql
    jdbc调用sparksql on yarn
    JDK错误
    JDK错误
    docker错误
    docker错误
    Django网站直接使用supervisor部署
    Django网站直接使用supervisor部署
  • 原文地址:https://www.cnblogs.com/webor2006/p/3515676.html
Copyright © 2011-2022 走看看