Understanding Unix/Linux Programming-信号与play_again4.c的准备知识

来源:互联网 发布:sql回滚语句 编辑:程序博客网 时间:2024/04/28 23:14
  • Ctrl-C做了什么?
  •   Ctrl-C终止当前运行的程序,这个中断由一个称为信号的内核机制产生。信号是一个简单而重要的概念,下面将探讨信号的基本概念。

      终端驱动程序在这里起到了相应的作用:

    1. 用户输入Ctrl-C
    2. 驱动程序收到字符
    3. 匹配VINTR和ISIG的字符被开启
    4. 驱动程序调用信号系统
    5. 信号系统发送SIGINT到进程
    6. 进程收到SIGINT
    7. 进程消亡

      当然未必一定是Ctrl-C作为中断的控制字符,这是可以更改驱动设置的。

    • 什么是信号:

      信号是由单个词组成的消息。绿灯、停止标牌、裁判手势等都是信号,而这个物体和事件不是消息,走、停和出界才是消息。当按下Ctrl-C时,内核向当前正在运行的进程发送中断信号,每个信号都有一个数字编码,中断信号编码通常是2。

      信号从何处来?

      信号来自内核,生成信号请求来自于3个地方:

    1. 用户:用户通过输入控制字符请求内核产生信号
    2. 内核:当进程执行出错时,内核给进程发送一个信号,例如:非法段存取、浮点数溢出等等;内核也利用信号通知进程特定事件的发生。
    3. 进程:一个进程可以通过系统调用kill命令给另一个进程发送信号,进程之间可以通过信号通信。
      1. 由进程某个操作产生的信号被成为同步信号,例如,被零除。
      2. 由用户击键这样的外部事件产生的信号被成为异步信号

      哪里可以找到信号列表?信号编号以及它们的名字一般出现在/usr/include/signal.h中。

      例如,中断信号被成为SIGINT,退出信号为SIGQUIT,非法段存取的信号是SIGSGEV。

      信号的作用?视情况而定。很多信号杀死进程。某时刻进程还在运行,下一秒它就消亡了。从内存中被删除,相应的所有的文件描述符被关闭,并且从进程表中被删除。使用SIGINT可以消灭一个进程,但是进程也有办法保护自己不被杀死。

    • 进程如何处理信号?

      当进程接收到SIGINT时,并不一定要消亡,进程能够通过系统调用signal告诉内核,它要如何处理信号,进程有3个选择:

    • 接收组织(内核)安排:通常是消亡

        手册上会列出对每个信号的默认处理,SIGINT的默认处理是消亡,进程并不一定要使用默认处理,但是可以通过一下调用来恢复默认处理:

        signal(SIGINT , SIG_DFL);

    • 忽略信号(喂?你好?什么?我听不清!喂?我听不清!)

        程序可以通过以下调用告诉内核它要忽略SIGINT信号

        signal(SIG_INT , SIG_IGN);

    • 调用一个函数

        这当然是最灵活有用的一种咯,考虑play_again3的例子。当用户输入Ctrl-C的时候,当前程序立即退出而不调用恢复终端驱动设置恢复的函数。更好的做法时,程序在接收到SIGINT后,调用一个恢复设置的函数,然后再退出。

        调用signal的第三种选择允许这种类型的响应。程序能够告诉内核,当信号到来时,应该调用哪个函数。在信号到来时调用的函数被成为信号处理函数(越看越觉得像是单片机编程中的中断处理函数)。为安装信号处理函数,程序调用:

        signal( signum , functionname );

      signal的返回值为-1时表示错误;而正常情况下,返回一个指向(前一个处理)函数的指针。

    来看看信号处理的例子吧:

     

    #include <stdio.h>#include <stdlib.h>#include <signal.h>void f(int) ;int main(){    void f(int) ;    int i ;    signal(SIGINT , f) ; // Declare the handler    for(i = 0 ; i < 5 ; i ++ ){        printf("Hello!\n" );        sleep(1) ;    }    return 0 ;}void f(int signum ){    printf("OUCH!\n");}

     

    很简单的例子,哈哈,下面一个例子会忽略Ctrl-C的信号,和书上不太一样,直接改上面的了:

     1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <signal.h> 4  5 void f(int) ; 6  7 int main() 8 { 9     void f(int) ;10     int i ;11 12     signal(SIGINT , SIG_IGN) ; // Declare the handler13 14     for(i = 0 ; i < 5 ; i ++ ){15         printf("Hello!\n" );16         sleep(1) ;17     }18 19     return 0 ;20 }21 22 void f(int signum )23 {24     printf("OUCH!\n");25 }

    在输出Hello!的过程中,Ctrl-C是不能产生中断的,而使用Ctrl-\是可以的,因为这个程序没有忽略或者捕捉SIGQUIT。相当于屏蔽了一个中断,却没有屏蔽另外一个中断。

    • 进程终止和为设备编程

      程序使用signal来告诉内核它需要忽略哪些信号,但是,对于程序员而言,有两个信号是不能被忽略和捕捉的,书上让我们自己去找。。。

    这个我就偷个懒,以后再找咯

    •  为设备编程:

      终端控制程序的三个方面:

    1. 驱动程序的属性和设置
    2. 以应用程序的特定需求来调整驱动程序,满足这些需求
    3. 处理信号报告的错误或者处理特定事件
    0 0
    原创粉丝点击