信号

Linux里信号是系统响应了某些条件而生成的一个事件,捕获到该信号的进程会相应地采取一些行动;信号是由于某些错误条件造成的,比如内存段冲突,浮点处理器错误或者非法指令等;它们由shell和终端处理器生成来引起中断,还可以作为在进程间传递消息或者修改行为的一种方式,明确地由一个进程发送给另一个进程

所有信号都在头文件signal.h里定义,以SIG开头,有兴趣可以自行搜索

如果进程接收到一个信号,但是事先并没有安排来捕获它,进程就会立即终止,通常系统会生成核心转储文件core,并存在当前目录下;这个文件是进程在内存中的映像,大家都都知道的,可以用来调试定位

通常Ctrl+C就会向前台进程也就是当前运行的程序发送SIGINT信号,这将引起该程序的终止,除非它事先安排了捕获这个信号

signal库函数可以用来处理信号,定义如下:

#include <signal.h>

void (*signal(int sig, void(*func)(int)))(int);

看到这函数我也是醉了,signal带了sig和func两个参数,准备捕获或者忽略的信号又参数sig给出,接收到指定的信号后将要调用的函数由参数func给出,信号处理函数必须有一个int类型的参数,也就是向信号处理程序传送一个整形参数,也就是接收到的信号代码,并返回void

下面的程序响应用户输入的Ctrl+C,第一次会打印一条信息并没有终止程序的运行,而第二次Ctrl+C的时候,程序结束运行:

lihui@2015 ~
$ cat he.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void ouch(int sig){
    printf("OUCH! - I got signal %d\n", sig);
    (void)signal(SIGINT, SIG_DFL);
}

int main(){
    (void)signal(SIGINT, ouch);

    while(1){
        printf("Hello World!\n");
        sleep(1);
    }
    return 0;
}

lihui@2015 ~
$ ./a.exe
Hello World!
Hello World!
Hello World!
^C
OUCH! - I got signal 2
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
^C

lihui@2015 ~
$

第一次Ctrl+C会让程序做出响应,然后程序继续运行,再次Ctrl+C,程序就会结束运行,因为SIGINT信号的处理方式已经恢复为默认行为,终止程序运行

这里的SIG_DFL含义是恢复默认行为,也就是ouch来处理了按下Ctrl+C所产生的SIGINT信号,程序会在ouch函数处理完毕之后继续执行,但是信号处理方式已经恢复到默认行为,当接收到第二个SIGINT信号后,会采取默认的行动,终止程序的运行

这里信号处理函数signal使用了一个整型参数SIGINT(终端中断),它就是引起该函数被调用的信号代码,如果需要在一个函数里处理多个信号,这个参数就很有用了,可以使用不同信号的名字来处理,当然这里打印出来了SIGINT的值为2

试想,如果把ouch里的signal去掉会怎么样,谁有兴趣可以试试~!

发表评论