1. 用户输入命令,在Shell下启动一个前台进程。
2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断。
3. 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用户态切换到内核态处理硬件中断。
4. 终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一个SIGINT信号给该进程)。
5. 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。
用kill -l命令可以察看系统定义的信号列表:
每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定义#define SIGINT 2。编号34以上的是实时信号,这些信号各自在什么条件下产生,默认的处理动作是什么(Term表示终止当前进程,Core表示终止当前进程并且Core Dump,Ign表示忽略该信号,Stop表示停止当前进程,Cont表示继续执行先前停止的进程),在signal(7)中都有详细说明。
0~31 不可靠信号,多个信号不会排队只保留一个,即信号可能丢失。
34~64 可靠(实时信号),支持排队信号不会丢失,可使用sigqueue发送信号,不像0~31有缺省的定义。
二、产生信号的条件主要有:
1、用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,例如Ctrl-C产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-Z产生SIGTSTP信号。
2、硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。
3、再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
4、一个进程调用kill(2)函数可以发送信号给另一个进程。
5、可以用kill(1)命令发送信号给某个进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。
6、raise:给自己发送信号。raise(sig)等价于kill(getpid(), sig);
7、killpg:给进程组发送信号。killpg(pgrp, sig)等价于kill(-pgrp, sig);
8、sigqueue:给进程发送信号,支持排队,可以附带信息。
9、当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。
三、用