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

  • 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!
" );
        sleep(1) ;
    }

    return 0 ;
}

void f(int signum )
{
    printf("OUCH!
");
}

很简单的例子,哈哈,下面一个例子会忽略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 handler
13 
14     for(i = 0 ; i < 5 ; i ++ ){
15         printf("Hello!
" );
16         sleep(1) ;
17     }
18 
19     return 0 ;
20 }
21 
22 void f(int signum )
23 {
24     printf("OUCH!
");
25 }

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

  • 进程终止和为设备编程

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

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

  •  为设备编程:

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

  1. 驱动程序的属性和设置
  2. 以应用程序的特定需求来调整驱动程序,满足这些需求
  3. 处理信号报告的错误或者处理特定事件
原文地址:https://www.cnblogs.com/NJdonghao/p/5304714.html