基本概念

信号是事件发生时对进程的通知机制。有时也称为软件中断,信号与硬件中断相似之处在于打断了程序执行的正常流程,大多数情况下,无法预测信号到达的精确时间。
一个具有合适权限的进程能够向另一进程发送信号,信号的这一用法可作为一种同步技术,甚至是进程通信IPC的原始形式。进程也可以向自身发送信号。然而发往进程的诸多信号,通常都是源于内核。
引发内核为进程产生信号的各类事件如下:
硬件发生异常:硬件异常的例子包括执行一条异常的机器语言指令,如被0除,或者引用了无法访问的内存区域。

用户键入能够产生信号的中断特殊字符:包括中断字符(Control-C)

发生了软件事件:例如,针对文件描述符的输出变为有效,调整了中断窗口大小、定时器到期、进程执行的CPU时间超限、或者该进程的某个子进程退出

信号分两大类:

内核向进程通知事件,构成所谓传统或者标准信号,编号1~31。
实时信号
信号产生后,会稍后被传递给某一进行,而进程也会采取某些措施来响应信号,在产生和到达期间,信号处于等待(pending)状态。如果需要确保一段代码不为传递来的信号所中断,可将信号添加到信号掩码中,会阻止该信号的到达,直到稍后对其解除阻塞。进程可以使用各种系统调用对其信号掩码添加和移除信号。

信号到达后,进程视具体信号执行如下默认操作之一:
忽略信号:内核将信号丢弃
终止进程
产生核心转储文件,同时进程终止:核心转储文件包含对进程虚拟内存的镜像,可将其加载到调试器中以检查进程终止时的状态
停止进程:暂停进程的执行
于之前暂停后再度恢复进程的执行

除了根据特定信号而采取默认行为之外,程序也能改变信号到达时的响应行为,称为对信号的处置设置。程序可以将对信号的初值设置为如下之一:
采取默认行为
忽略信号
执行信号处理器(信号处理器程序是由程序员编写的函数,用于为响应传递来的信号而执行适当任务)

改变信号处置:signal()

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

关于signal()函数的声明理解可以参考文章分析C声明

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

static void sigHandler(int sig)
{
    printf("Ouch!\n");                  /* UNSAFE (see Section 21.1.2) */
}

int main(int argc, char *argv[])
{
    int j;

    if (signal(SIGINT, sigHandler) == SIG_ERR)
        errExit("signal");

    for (j = 0; ; j++) {
        printf("%d\n", j);
        sleep(3);                       /* Loop slowly... */
    }
}