《unix高级环境编程》信号——信号基本概述

信号基本概念

          信号本质是在软件层次上对中断机制的一种模拟,即软件中断;在原理上,一个进程收到一个信号或处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,进程也不知道信号到底什么时候到达。信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。

        信号事件的发生有两个来源:

  1. 硬件来源(比如按下了键盘一些信号指令或者其它硬件故障);
  2. 软件来源,最常用发送信号的系统函数是 kill,raise,alarmsetitimer 以及sigqueue 函数,软件来源还包括一些非法运算等操作。

        我们可以通过指令 kill -l 查看自己系统的信号,如下显示:

1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

信号的分类

不可靠信号:

        Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:信号的错误处理、信号可能丢失。因此,早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。


可靠信号(实时信号):
        可靠信号支持排队,不会丢失。同时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction(),可靠信号克服了信号可能丢失的问题。Linux在支持新版本的信号安装函数sigation() 以及信号发送函数sigqueue()的同时,仍然支持早期的signal()信号安装函数,支持信号发送函数kill()
        注意:信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关。信号值小于SIGRTMIN的信号为不可靠信号,信号值在SIGRTMIN及SIGRTMAX之间的信号为可靠信号。

信号产生

          产生信号的条件主要有:

  1. 用户在终端按下某些键时,引发终端产生的信号,终端驱动程序会发送信号给前台进程,例如Ctrl-C产生SIGINT信号,Ctrl-\产生 SIGQUIT 信号,Ctrl-Z 产生 SIGTSTP 信号。
  2. 硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
  3. 进程调用 kill(2) 函数可将信号发送给另一个进程或进程组。
  4. 用户调用 kill(1) 命令将信号发送给其他进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。
  5. 当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。

信号的处理

         进程可以通过三种方式来响应一个信号,采用上述三种方式的哪一个来响应信号,取决于传递给相应API函数的参数:

  1. 忽略信号,即对信号不做任何处理,其中SIGKILL及SIGSTOP两个信号不能忽略;
  2. 捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数;
  3. 执行缺省操作,Linux对每种信号都规定了默认操作。注意,进程对实时信号的缺省反应是进程终止。

信号与中断

         信号与中断的相似点:
  1. 采用了相同的异步通信方式;
  2. 当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
  3. 都在处理完毕后返回到原来的断点;
  4. 对信号或中断都可进行屏蔽。
        信号与中断的区别:
  1. 中断有优先级,而信号没有优先级,所有的信号都是平等的;
  2. 信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
  3. 中断响应是及时的,而信号响应通常都有较大的时间延迟。

signal 函数

/* signal 函数*/
/*
 * 函数功能:信号处理机制;
 * 返回值:若成功则返回信号以前的处理配置,若出错则返回SIG_ERR;
 * 函数原型:
 */
#include <signal.h>
void (*signal (int signo, void(*func)(int))) (int);
/*
 * 说明:
 * signo是信号名;
 * func是常量值SIG_IGN、SIG_DFL或当接到此信号后要调用的函数的地址,
 * 若指定常量SIG_IGN,则向内核表示忽略此信号(SIGKILL和SIGSTOP这两个信号不能忽略);
 * 若指定常量SIG_DFL,则表示接到此信号后的动作是系统默认动作;
 * 当指定函数地址时,则在信号发生时,调用该函数;
 *
 * signal函数需要两个参数,返回一个函数指针,而该指针所指向的函数无返回值;
 * 也就是说signal函数的返回值是一个函数地址,该函数有一个参数;
 * 可以简化上面的函数形式表达:
 */
typedef void Sigfunc(int);
Sigfunc *signal(int, Sigfunc*);

测试程序:

#include "apue.h"
#include <signal.h>

static void sig_sur(int signo);

int main(void)
{
    if(signal(SIGUSR1 , sig_sur) == SIG_ERR)
        err_sys("can't catch SIGUSR1");
    if(signal(SIGUSR2 , sig_sur) == SIG_ERR)
        err_sys("can't catch SIGUSR2");
    for(;;)
    {
        pause();
        printf("pause.\n");
    }

}

static void sig_sur(int signo)
{
    if(SIGUSR1 == signo)
        printf("recevied SIGUSR1.\n");
    else if(SIGUSR2 == signo)
        printf("recevied SIGUSR2.\n");
    else
        err_dump("recevied signal %d.\n",signo);
}
输出结果:

$ ./signal &
[1] 10128
$ kill -USR1 10128
recevied SIGUSR1.
pause.
$ kill -USR2 10128
recevied SIGUSR2.
pause.
$ kill  10128
[1]+  Terminated              ./signal
该程序是对信号SIGUSR1 和SIGUSR2进行捕捉,其他信号采用默认的终止进程。


参考资料:

http://blog.csdn.net/jnu_simba/article/details/8940602

http://blog.csdn.net/justin12zhu/article/details/2797647

http://galex.cn/%E3%80%90apue%E3%80%91%E4%BF%A1%E5%8F%B7/#一、概念

《UNIX高级环境编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值