以下是维基百科对信号的定义:
在计算机科学中,信号(英语:Signals)是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。
简单的理解信号就是一种Linux环境下进程通讯的一种机制。
一般情况下,信号的来源可分为以下三种:
- 硬件方式:除数为零、无效的存储访问等硬件异常产生信号。这些事件通常由硬件(如:CPU)检测到,并将其通知给Linux操作系统内核,然后内核生成相应的信号,并把信号发送给该事件发生时正在进行的程序。
- 软件方式:用户在终端下调用kill命令向进程发送任务信号、进程调用kill或sigqueue函数发送信号、当检测到某种软件条件已经具备时发出信号,如由alarm或settimer设置的定时器超时时将生成SIGALRM信号等多种情景均可产生信号。
- 键盘输入:当用户在终端上按下某键时,将产生信号。如按下组合键Ctrl+C将产生一个SIGINT信号,Ctrl+\产生一个SIGQUIT信号等。
在Shell下输入kill –l 可显示Linux 系统支持的全部信号,如下表所示:
可以看到Linux中系统一共支持64种信号,其中1到31号信号为普通信号(也程为不可靠信号),34到64为实时信号(可靠信号)。
- 可靠信号与不可靠信号的区别:
- 这里的不可靠主要是不支持信号队列,就是当多个信号发生在进程中的时候(收到信号的速度超过进程处理的速度的时候),这些没来的及处理的信号就会被丢掉,仅仅留下一个信号。
- 可靠信号是多个信号发送到进程的时候(收到信号的速度超过进程处理信号的速度的时候),这些没来的及处理的信号就会排入进程的队列。等进程有机会来处理的时候,依次再处理,信号不丢失。
我们平时可以接触的是普通信号,其各个信号的含义如下:
- SIGHUP :当用户退出Shell时,由该Shell启的发所有进程都退接收到这个信号,默认动作为终止进程。
- SIGINT :用户按下组合键时,用户端时向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。
- SIGQUIT :当用户按下组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程并产生core文件。
- SIGILL :CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件。
- SIGTRAP:该信号由断点指令或其他trap指令产生。默认动作为终止进程并产生core文件。
- SIGABRT :调用abort函数时产生该信号。默认动作为终止进程并产生core文件。
- SIGBUS:非法访问内存地址,包括内存地址对齐(alignment)出错,默认动作为终止进程并产生core文件。
- SIGFPE:在发生致命的算术错误时产生。不仅包括浮点运行错误,还包括溢出及除数为0等所有的算术错误。默认动作为终止进程并产生core文件。
- SIGKILL :无条件终止进程。本信号不能被忽略、处理和阻塞。默认动作为终止进程。它向系统管理员提供了一种可以杀死任何进程的方法。
- SIGUSR1:用户定义的信号,即程序可以在程序中定义并使用该信号。默认动作为终止进程。
- SIGSEGV:指示进程进行了无效的内存访问。默认动作为终止进程并使用该信号。默认动作为终止进程。
- SIGUSR2:这是另外一个用户定义信号,程序员可以在程序中定义并使用该信号。默认动作为终止进程。
- SIGPIPE :Broken pipe:向一个没有读端的管道写数据。默认动作为终止进程。
- SIGALRM :定时器超时,超时的时间由系统调用alarm设置。默认动作为终止进程。
- SIGTERM :程序结束(terminate)信号,与SIGKILL不同的是,该信号可以被阻塞和处理。通常用来要求程序正常退出。执行Shell命令kill时,缺少产生这个信号。默认动作为终止进程。
- SIGCHLD :子程序结束时,父进程会收到这个信号。默认动作为忽略该信号。
- SIGCONT:让一个暂停的进程继续执行。
- SIGSTOP:停止(stopped)进程的执行。注意它和SIGTERM以及SIGINT的区别:该进程还未结束,只是暂停执行。本信号不能被忽略、处理和阻塞。默认作为暂停进程。
- SIGTSTP:停止进程的动作,但该信号可以被处理和忽略。按下组合键时发出该信号。默认动作为暂停进程。
- SIGTTIN:当后台进程要从用户终端读数据时,该终端中的所有进程会收到SIGTTIN信号。默认动作为暂停进程。
- SIGTTOU:该信号类似于SIGTIN,在后台进程要向终端输出数据时产生。默认动作为暂停进程。
- SIGURG :套接字(socket)上有紧急数据时,向当前正在运行的进程发出此信号,报告有紧急数据到达。默认动作为忽略该信号。
- SIGXCPU:进程执行时间超过了分配给该进程的CPU时间,系统产生该信号并发送给该进程。默认动作为终止进程。
- SIGXFSZ:超过文件最大长度的限制。默认动作为yl终止进程并产生core文件。
- SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是它只计算该进程占有用的CPU时间。默认动作为终止进程。
- SIGPROF:类似于SIGVTALRM,它不仅包括该进程占用的CPU时间还抱括执行系统调用的时间。默认动作为终止进程。
- SIGWINCH:窗口大小改变时发出。默认动作为忽略该信号。
- SIGIO:此信号向进程指示发出一个异步IO事件。默认动作为忽略。
- SIGPWR:关机。默认动作为终止进程。
上面标注出来的信号是我们在学习过程中重点关注的信号,在Linux后期的学习中这些信号的身影将经常出现。
信号实质上是软中断,中断有优先级,信号也有优先级。如果一个进程有多个未决信号,则对于同一个未决的实时信号,内核将按照发送的顺序来递送信号。如果存在多个未决信号,则值(或者说编号)越小的越先被递送。如果即存在不可靠信号,又存在可靠信号(实时信号),虽然POSIX对这一情况没有明确规定,但Linux系统和大多数遵循POSIX标准的操作系统一样,将优先递送不可靠信号。
当信号发生时,用户可以要求进程以下列3种方式之一对信号做出响应。
1、 捕捉信号:对于要捕捉的信号,可以为其指定信号处理函数,信号发生时该函数自动被调用,在该函数内部实现对该信号的处理。(ps:更多捕捉信号的细节请看另一篇文章:Linux信号捕捉及其处理)
2、 忽略信号:宏定义为SIG_IGN大多数信号都可使用这种方式进行处理,但是SIGKILL和SIGSTOP这两个信号不能被忽略,同时这两个信号也不能被捕获和阻塞。此外,如果忽略某某些由硬件异常产生的信号(如非法存储访问或除以0),则进程的行为是不可预测的。
3、 按照系统默认方式处理,宏定义为SIG_DFL。大部分信号的默认操作是终止进程,且所有的实时信号的默认动作都是终止进程。
程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP
不能恢复至默认动作的信号有:SIGILL,SIGTRAP
默认会导致进程流产的信号有:SIGABRT、SIGBUS、SIGFPE、SIGILL、SIGIOT、SIGQUIT、SIGSEGV、SIGTRAP、SIGXCPU、SIGXFSZ
默认会导致进程退出的信号有:SIGALRM、SIGHUP、SIGINT、SIGKILL、SIGPIPE、SIGPOLL、SIGPROF、SIGSYS、SIGTERM、SIGUSR1、SIGUSR2、SIGVTALRM
默认会导致进程停止的信号有:SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU
默认进程忽略的信号有:SIGCHLD、SIGPWR、SIGURG、SIGWINCH
至此,Linux信号入门的相关知识已经介绍完了,Linux的处理机制和底层细节请看关于信号的其他文章。