Linux环境编程之信号(一):信号基本概述
引言
假如在后台运行一个可执行程序./a.out,如果想终止该程序,通常会按下Ctrl-C,从而产生一个中断,其实这个过程的实现就是通过信号完成的。信号是软件中断,它提供了一种处理异步事件的方法。
(一)
每个信号都有一个名字,这些名字都以三个字符SIG开头。例如SIGALARM是闹钟信号,当由alarm函数设置的计时器超时后产生此信号。Linux除支持31种不同信号外,还支持应用程序额外定义信号。信号定义在<bits/signum.h>中,也可以通过命令kill -l查看。
(二)信号的产生
信号是如何产生的呢,下列方式均可产生信号:
1、当用户按某些终端键时,引发终端产生的信号。
2、硬件异常产生信号:除数为0、无效的内存引用等等。
3、进程调用kill(2)函数可将信号发送给另一个进程或进程组。
4、用户可用kill(1)命令将信号发送给其他进程。
5、当检测到某种软件条件已经发生,并应将其通知有关进程时也产生信号。
(三)信号的处理
进程不能简单地测试一个变量来判别是否出现了一个信号,而是必须告诉内核“在此信号出现时,请执行下列操作”。信号的处理包括三种方式:忽略信号、捕捉信号、执行系统默认动作。
注意:
1、大多数信号都可以使用忽略信号的方式进行处理,但对于SIGKILL和SIGSTOP信号则不能忽略,因为它们向超级用户提供了使进程终止或停止的可靠方法。
2、为了捕捉信号,要通知内核在某种信号发生时调用一个用户函数。SIGKILL和SIGSTOP信号不能被捕捉。
3、大多数信号的系统默认动作是终止进程。
(三)signal函数示例
信号机制最简单的接口就是signal函数。原型如下:
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
signo是以SIG三个字母开头的信号名。func的值是常量SIG_IGN(忽略此信号)、常量SIG_DFL(系统默认动作)或当接到此信号后要调用的函数地址(信号发生时,调用该函数,即信号处理程序)。
/* *File Name:signal.c *Author : libing *Mail : libing1209@126.com */ #include <stdio.h> #include <stdlib.h> #include <signal.h> static void sig_usr(int); int main(void) { if(signal(SIGUSR1, sig_usr) == SIG_ERR)//signal函数 printf("can‘t catch SIGUSR1"); if(signal(SIGUSR2, sig_usr) == SIG_ERR) printf("can‘t catch SIGUSR2"); for(;;) pause(); /*go to sleep, waiting for signal*/ return 0; } static void sig_usr(int signo) { if(signo == SIGUSR1) printf("received SIGUSR1.\n"); else if(signo == SIGUSR2) printf("received SIGUSR2.\n"); else printf("received signal %d\n", signo); }程序测试:
编译:gcc signal.c -o signal 运行:./signal & 测试:kill -USR1 8522 kill -USR2 8522 kill 8522注意:kill命令和kill函数只是将一个信号送给一个进程或进程组。信号是否终止进程则取决于信号的类型,以及进程是否安排了捕捉该信号。